package com.mzj.saas.jobs.bill.service;


import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.haixiaoke.saas.repository.service.ISubscribeService;
import com.haixiaoke.saas.repository.service.impl.SubscribeServiceImpl;
import com.haixiaoke.saas.repository.vo.SubscribeVo;
import com.mzj.saas.commons.enums.*;
import com.mzj.saas.commons.util.BeanUtils;
import com.mzj.saas.commons.util.DataUtils;
import com.mzj.saas.jobs.EnterpriseData.entity.User;
import com.mzj.saas.jobs.EnterpriseData.repository.UserRepository;
import com.mzj.saas.jobs.backlog.entity.BacklogItem;
import com.mzj.saas.jobs.backlog.entity.SmartLock;
import com.mzj.saas.jobs.backlog.repository.BacklogItemRepository;
import com.mzj.saas.jobs.backlog.repository.SmartLockRepository;
import com.mzj.saas.jobs.bill.entity.*;
import com.mzj.saas.jobs.bill.repository.*;
import com.mzj.saas.jobs.bill.vo.HouseVO;
import com.mzj.saas.jobs.commons.ResultBean;
import com.mzj.saas.jobs.commons.StatusCode;
import com.mzj.saas.jobs.config.sms.SmsConfig;
import com.mzj.saas.jobs.lock.entity.SmartLockBrand;
import com.mzj.saas.jobs.lock.repository.HouseLockFrozenLogRepository;
import com.mzj.saas.jobs.lock.repository.SmartLockBrandRepository;
import com.mzj.saas.jobs.lock.service.SmartLockBrandService;
import com.mzj.saas.jobs.lock.vo.yaluete.SmartLockVO;
import com.mzj.saas.jobs.redis.RedisService;
import com.mzj.saas.jobs.sms.service.SmsService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static java.lang.Double.parseDouble;

/**
 * 新的账单生成Service--启用   【提前30天生成当前账单】
 */
@Service
public class GenerateBillService {
    private static Logger log = LoggerFactory.getLogger(GenerateBillService.class);

    @Autowired
    private RedisService redisService;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private HouseRepository houseRepository;
    @Autowired
    private HouseContractRepository houseContractRepository;
    @Autowired
    private HouseExpenseOtherRepository houseExpenseOtherRepository;
    @Autowired
    private RentBillRepository rentBillRepository;
    @Autowired
    private RentBillRelationRepository rentBillRelationRepository;
    @Autowired
    private ExpenseBillRepository expenseBillRepository;
    @Autowired
    private ExpenseBillRelationRepository expenseBillRelationRepository;
    @Autowired
    private HouseMatchUserRepository houseMatchUserRepository;
    @Autowired
    private EstateRentBillRepository estateRentBillRepository;
    @Autowired
    private CommunityHouseUserRepository communityHouseUserRepository;
    @Autowired
    private EstateExpenseBillRepository estateExpenseBillRepository;
    @Autowired
    private HouseWaitPaymentDetailRepository houseWaitPaymentDetailRepository;
    @Autowired
    private EstateExpenseBillDetailRepository estateExpenseBillDetailRepository;
    @Autowired
    private DepartmentBillRepository departmentBillRepository;
    @Autowired
    private HouseRemainingRepository houseRemainingRepository;
    @Autowired
    private HouseRemainingRecordRepository houseRemainingRecordRepository;
    @Autowired
    private HouseRemainingRelationRepository houseRemainingRelationRepository;
    @Autowired
    private AppUserRepository appUserRepository;
    @Autowired
    private BacklogItemHouseRemainingRepository backlogItemHouseRemainingRepository;
    @Autowired
    private BacklogItemRepository backlogItemRepository;
    @Autowired
    private BacklogItemPropertyOtherBillRepository backlogItemPropertyOtherBillRepository;
    @Autowired
    private BacklogItemPropertyRentBillRepository backlogItemPropertyRentBillRepository;
    @Autowired
    private SmartLockAuthRepository smartLockAuthRepository;
    @Autowired
    private SmartLockBleRepository smartLockBleRepository;
    @Autowired
    private SmartLockPwdRepository smartLockPwdRepository;
    @Autowired
    private SmartLockCardRepository smartLockCardRepository;
    @Autowired
    private SmartLockFingerprintRepository smartLockFingerprintRepository;
    @Autowired
    private SmartLockFaceRepository smartLockFaceRepository;
    @Autowired
    private SmartLockRepository smartLockRepository;
    @Autowired
    private LockFrozenRepository lockFrozenRepository;
    @Autowired
    private SmartLockBrandService smartLockBrandService;
    @Autowired
    private SmartLockBrandRepository smartLockBrandRepository;
    @Autowired
    private HouseLockFrozenLogRepository houseLockFrozenLogRepository;
    @Autowired
    private SmsService smsService;
    @Autowired
    private SmsConfig smsConfig;
    @Autowired
    private BacklogItemCardRefRepository backlogItemCardRefRepository;
    @Autowired
    private EstateViolateBillRepository estateViolateBillRepository;
    @Autowired
    private HouseExpenseBillRuleRepository houseExpenseBillRuleRepository;
    @Autowired
    private BacklogItemHouseOtherBillRepository backlogItemHouseOtherBillRepository;
    @Autowired
    private CohabitRepository cohabitRepository;
    @Autowired
    private MatchUserHouseRepository matchUserHouseRepository;
    @Autowired
    private MatchUserRepository matchUserRepository;
    @Autowired
    private DepartmentRemainingRepository departmentRemainingRepository;
    @Autowired
    private DepartmentRemainingRefRepository departmentRemainingRefRepository;
    @Autowired
    private DepartmentRemainingRecordRepository departmentRemainingRecordRepository;
    @Autowired
    private UserDepartmentRefRepository userDepartmentRefRepository;
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private ISubscribeService subscribeService;

    public String work() throws Exception {

        // 公租房账单
        houseRentBill();
        houseOtherBill();

        // 物业房产账单
        propertyRentBill();
        propertyOtherBill();

        // 余额扣减账单
        remainingDeductionBill();

        // 违约金账单增长
        violateBillGrowth();

        return "SUCCESS";
    }

    private void violateBillGrowth() {
        try {
            log.info("违约金账单增长 start");
            List<EstateViolateBill> estateViolateBillList = estateViolateBillRepository.findByPaymentStatusAndLeaseStatus(0,0);
            for (EstateViolateBill estateViolateBill : estateViolateBillList) {
                if (estateViolateBill.getStatus() == 0) {
                    Integer growthCost = estateViolateBill.getGrowthCost();
                    Integer cost = estateViolateBill.getCost();
                    estateViolateBill.setCost(cost + growthCost);
                }
            }
            estateViolateBillRepository.saveAll(estateViolateBillList);
            log.info("违约金账单增长 end");
        } catch (Exception e) {
            log.error("违约金账单增长异常 " + e.getMessage(), e);
        }
    }


    // 公租房账单-生成租金账单
    public void houseRentBill() throws Exception {
        try {
            log.info("公租房账单-生成租金账单明细  start");

            // 当前时间 [凌晨2点跑前一天的数据]
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            Calendar cal = Calendar.getInstance();
            cal.setTime(new Date());
            cal.add(Calendar.DAY_OF_MONTH, -1);
            cal.add(Calendar.DAY_OF_MONTH, 30);
            Date currentDate = df.parse(df.format(cal.getTime())); // cal.getTime()
            log.info("公租房账单-生成租金账单 当前跑 " + currentDate + "日期的账单");
            String ruleSql = "select f.house_id as houseId, r.charge_type as chargeType,r.start_time AS startTime,r.end_time AS endTime,r.close_time AS closeTime,"
                    + " r.expense_id AS expenseId,r.flag ,r.day ,r.create_time AS createTime ,r.id,r.date_flag AS dateFlag,r.collection_org as collectionOrg   "
                    + " from saas_house_expense_rule_ref f left join saas_house_expense_bill_rule r "
                    + "on f.rule_id = r.id where r.charge_type in(8) and f.house_nature = 1  ";


            // 查询账单生成规则数据
            List<Map<String, Object>> ruleList = jdbcTemplate.queryForList(ruleSql);
            if (CollectionUtils.isEmpty(ruleList)) {
                log.info(" 公租房账单-生成租金- 没有租金账单规则数据  end");
                return;
            }

            // 收费项目id集合
            List<String> expenseId = new ArrayList<>();
            // 公租房id集合
            List<String> hIds = new ArrayList<>();

            for (Map<String, Object> k : ruleList) {
                hIds.add(k.get("houseId").toString());
                expenseId.add(k.get("expenseId").toString());
            }

            hIds = hIds.stream().distinct().collect(Collectors.toList());

            // 查询收费项目
            List<HouseExpenseOther> projectList = houseExpenseOtherRepository.findByIdIn(expenseId);
            if (projectList.size() == 0) {
                log.info(" 公租房账单-生成租金 -- 没有收费项目数据  end");
                return;
            }

            // 公租房信息
            List<House> houseList = houseRepository.findByIdIn(hIds);
            // 公租房信息Map
            Map<String, List<House>> houseMap = houseList.stream().collect(Collectors.groupingBy(House::getId));
            // 合同资料Map
            Map<String, List<HouseContract>> houseContractMap = houseContractRepository.findByHouseIdIn(hIds).stream().collect(Collectors.groupingBy(HouseContract::getHouseId));
            // 账单生成规则信息
            Map<String, List<Map<String, Object>>> ruleMap = ruleList.stream().collect(Collectors.groupingBy((Map<String, Object> m) -> m.get("houseId") + "_" + m.get("chargeType")));

            // houseId_chargeType
            for (String houseIdStr : ruleMap.keySet()) {

                String hct[] = houseIdStr.split("_");
                String houseId = hct[0];
                Integer chargeType = Integer.parseInt(hct[1]);

                // 规则信息
                List<Map<String, Object>> rList = ruleMap.get(houseIdStr);
                if (CollectionUtils.isEmpty(rList)) {
                    log.warn("公租房账单-生成租金 -- 未找到规则信息  houseId={}", houseIdStr);
                    continue;
                }
                Map<String, Object> rMap = rList.get(0);

                // 公租房信息
                List<House> hList = houseMap.get(houseId);
                if (CollectionUtils.isEmpty(hList)) {
                    log.warn("公租房账单-生成租金 --  未找到公租房信息 houseId={}", houseId);
                    continue;
                }
                House house = hList.get(0);

                // 合同信息
                List<HouseContract> cList = houseContractMap.get(house.getId());
                if (CollectionUtils.isEmpty(cList)) {
                    log.warn("公租房账单-生成租金 --  未找到合同信息 houseId={}", houseId);
                    continue;
                }
                HouseContract houseContract = cList.get(0);
                Integer flag = (Integer) rMap.get("flag");
                Integer day = (Integer) rMap.get("day");
                Object dateFlagObj = rMap.get("dateFlag");
                // 收款单位
                Long collectionOrg = (Long) rMap.get("collectionOrg");

                List<RentBill> rentBillList = rentBillRepository.findByHouseIdAndChargeTypeOrderByCreateTimeAsc(houseId, 1);  // chargeType 收费项目:1租金 2押金
                RentBill endRentBill = rentBillList.get(0); // 第一年账单
                Date endTime = endRentBill.getEndTime();

                // 计算合同未生成账单的时间周期，按合同设置方式生成
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(endTime);
                calendar.add(Calendar.DAY_OF_MONTH, 1);
                Date startDate = df.parse(df.format(calendar.getTime()));// 开始时间 = 第一年账单结束时间 + 1天
                Date endDate = df.parse(df.format(houseContract.getEntTime()));

                // 规则生成时间
                Calendar calen = Calendar.getInstance();
                calen.setTime((Date) rMap.get("createTime"));
                calen.add(Calendar.DAY_OF_MONTH, 30);
                String createTime = df.format(calen.getTime());
                String rid = (String) rMap.get("id");

                // 只生成当前时间在时间周期内的账单
                if (currentDate.getTime() >= startDate.getTime() && currentDate.getTime() <= endDate.getTime()) {
                    log.info("公租房账单-生成租金 -- 生成当前时间在时间周期内的账单 ");
                    // 拆分时间段
                    Integer payType = houseContract.getPayType(); // 缴纳方式：1首次年付，后续按月 2首次年付、后续按季 3首次年付，后续按半年 4首次年付，后续按年
                    List<Map<String, String>> dateList = new ArrayList<>();
                    Date tempDate = startDate;
                    BigDecimal month = new BigDecimal(1);
                    switch (payType) {
                        case 1:
                            dateList = dateList(tempDate, endDate, 1);
                            month = new BigDecimal(1);
                            break;
                        case 2:
                            dateList = dateList(tempDate, endDate, 3);
                            month = new BigDecimal(3);
                            break;
                        case 3:
                            dateList = dateList(tempDate, endDate, 6);
                            month = new BigDecimal(6);
                            break;
                        case 4:
                            dateList = dateList(tempDate, endDate, 12);
                            month = new BigDecimal(12);
                            break;
                    }

                    String cDate = df.format(currentDate);

                    // 规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                    Boolean flags = false;
                    if (cDate.equals(createTime)) {
                        flags = true;
                    }

                    log.info("公租房账单-生成租金 -- 拆分时间段数据 dateList={} ", JSONObject.toJSONString(dateList));

                    for (Map<String, String> m : dateList) {
                        String start = m.get("start");
                        String end = m.get("end");

                        // 获取截止时间
                        Date startTimes = df.parse(start);
                        if (dateFlagObj != null) {
                            Integer dateFlag = (Integer) dateFlagObj; // 时间标志：1开始时间 2结束时间
                            if (dateFlag.equals(2)) {
                                startTimes = df.parse(end);
                            }
                        }
                        Date closeTime = null;
                        if (flag.equals(1)) {  // 1前 2后
                            Calendar c = Calendar.getInstance();
                            c.setTime(startTimes);
                            c.add(Calendar.DAY_OF_MONTH, -day);
                            closeTime = c.getTime();
                        } else {
                            Calendar c = Calendar.getInstance();
                            c.setTime(startTimes);
                            c.add(Calendar.DAY_OF_MONTH, day);
                            closeTime = c.getTime();
                        }

                        log.info("公租房账单-生成租金 -- 判断是否生成账单  ", JSONObject.toJSONString(dateList));
                        //(当前时间 == 开始时间) 或者 (规则生成时间 == 当前时间和开始时间 < 当前时间)
                        if (cDate.equals(start) || (flags && df.parse(start).getTime() < currentDate.getTime())) {
                            // 按对应方式生成账单
                            Integer billChargeType = 1;
                            // 租金 = 面积 * 单价 * 天数
                            BigDecimal rentUnitAmount = new BigDecimal(houseContract.getRentUnitAmount());

                            // int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                            BigDecimal temp = houseContract.getHousingArea().multiply(rentUnitAmount).multiply(month);
                            Integer cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());

                            // 生成租金账单

                            RentBill rentBill = new RentBill();
                            rentBill.setContractNubmer(house.getContractNumber());
                            rentBill.setHouseId(houseId);
                            rentBill.setChargeType(billChargeType);
                            rentBill.setCommunityId(house.getResidenceCommunityId());
                            rentBill.setBuildingNum(house.getBuildingNum());
                            rentBill.setUnit(house.getUnit());
                            if (collectionOrg == null) {
                                rentBill.setOrgId(house.getOrgId());
                            } else {
                                rentBill.setOrgId(collectionOrg);
                            }
                            rentBill.setPaymentStatus(0);
                            rentBill.setRoomNumber(house.getRoomNumber());
                            rentBill.setMatchUserId(houseContract.getMatchUserId());
                            rentBill.setCost(cose);
                            rentBill.setMeasureUnit("元/平方米/月");
                            rentBill.setStartTime(df.parse(start));
                            rentBill.setEndTime(df.parse(end));
                            rentBill.setShouldPayTime(closeTime);
                            rentBill.setCreateTime(new Date());
                            rentBill.setBillType(1);
                            rentBill.setAuditStatus(0);
                            rentBill.setRuleId(rid);


                            rentBillRepository.save(rentBill);
                            // 公租房合同与租金/押金账单关系表
                            RentBillRelation relation = new RentBillRelation();
                            relation.setHouseId(rentBill.getHouseId());
                            relation.setRentBillId(rentBill.getId());
                            relation.setMatchUserId(rentBill.getMatchUserId());
                            relation.setContractNubmer(houseContract.getContractNubmer());
                            rentBillRelationRepository.save(relation);

                        }
                    }

                } else {
                    log.info("公租房账单-生成租金 -- 生成当前时间不在时间周期内的账单  ");
                    // 当前时间不在时间周期内的账单
                    // 整个周期账单小于当前时间
                    log.info("公租房账单-生成租金 -- 整个周期账单小于当前时间  ");
                    if (currentDate.getTime() > startDate.getTime() && currentDate.getTime() > endDate.getTime()) {
                        // 规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                        String curr = df.format(currentDate);
                        if (curr.equals(createTime)) {
                            // 拆分时间段
                            Integer payType = houseContract.getPayType(); // 缴纳方式：1首次年付，后续按月 2首次年付、后续按季 3首次年付，后续按半年 4首次年付，后续按年
                            List<Map<String, String>> dateList = new ArrayList<>();
                            Date tempDate = startDate;
                            BigDecimal month = new BigDecimal(1);
                            switch (payType) {
                                case 1:
                                    dateList = dateList(tempDate, endDate, 1);
                                    month = new BigDecimal(1);
                                    break;
                                case 2:
                                    dateList = dateList(tempDate, endDate, 3);
                                    month = new BigDecimal(3);
                                    break;
                                case 3:
                                    dateList = dateList(tempDate, endDate, 6);
                                    month = new BigDecimal(6);
                                    break;
                                case 4:
                                    dateList = dateList(tempDate, endDate, 12);
                                    month = new BigDecimal(12);
                                    break;
                            }

                            for (Map<String, String> m : dateList) {
                                String start = m.get("start");
                                String end = m.get("end");

                                // 获取截止时间
                                Date startTimes = df.parse(start);

                                if (dateFlagObj != null) {
                                    Integer dateFlag = (Integer) dateFlagObj; // 时间标志：1开始时间 2结束时间
                                    if (dateFlag.equals(2)) {
                                        startTimes = df.parse(end);
                                    }
                                }

                                Date closeTime = null;
                                if (flag.equals(1)) {  // 1前 2后
                                    Calendar c = Calendar.getInstance();
                                    c.setTime(startTimes);
                                    c.add(Calendar.DAY_OF_MONTH, -day);
                                    closeTime = c.getTime();
                                } else {
                                    Calendar c = Calendar.getInstance();
                                    c.setTime(startTimes);
                                    c.add(Calendar.DAY_OF_MONTH, day);
                                    closeTime = c.getTime();
                                }

                                // 按对应方式生成账单
                                Integer billChargeType = 1;
                                // 租金 = 面积 * 单价 * 天数
                                BigDecimal rentUnitAmount = new BigDecimal(houseContract.getRentUnitAmount());

                                // int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                                BigDecimal temp = houseContract.getHousingArea().multiply(rentUnitAmount).multiply(month);
                                Integer cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());

                                // 生成租金账单

                                RentBill rentBill = new RentBill();
                                rentBill.setContractNubmer(house.getContractNumber());
                                rentBill.setHouseId(houseId);
                                rentBill.setChargeType(billChargeType);
                                rentBill.setCommunityId(house.getResidenceCommunityId());
                                rentBill.setBuildingNum(house.getBuildingNum());
                                rentBill.setUnit(house.getUnit());
                                if (collectionOrg == null) {
                                    rentBill.setOrgId(house.getOrgId());
                                } else {
                                    rentBill.setOrgId(collectionOrg);
                                }
                                rentBill.setPaymentStatus(0);
                                rentBill.setRoomNumber(house.getRoomNumber());
                                rentBill.setMatchUserId(houseContract.getMatchUserId());
                                rentBill.setCost(cose);
                                rentBill.setMeasureUnit("元/平方米/月");
                                rentBill.setStartTime(df.parse(start));
                                rentBill.setEndTime(df.parse(end));
                                rentBill.setShouldPayTime(closeTime);
                                rentBill.setCreateTime(new Date());
                                rentBill.setBillType(1);
                                rentBill.setAuditStatus(0);
                                rentBill.setRuleId(rid);

                                rentBillRepository.save(rentBill);
                                // 公租房合同与租金/押金账单关系表
                                RentBillRelation relation = new RentBillRelation();
                                relation.setHouseId(rentBill.getHouseId());
                                relation.setRentBillId(rentBill.getId());
                                relation.setMatchUserId(rentBill.getMatchUserId());
                                relation.setContractNubmer(houseContract.getContractNubmer());
                                rentBillRelationRepository.save(relation);

                            }

                        }

                    }


                }

            }

            log.info("生成租金账单明细  end");

        } catch (Exception e) {
            log.error("生成租金账单明细异常  " + e.getMessage(), e);
        }
    }

    // 公租房账单-其它费用账单
    public void houseOtherBill() throws Exception {
        try {
            log.info("生成其它费用账单明细  start");

            // 当前时间 [凌晨2点跑前一天的数据]
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            Calendar cal = Calendar.getInstance();
            cal.setTime(new Date());
            cal.add(Calendar.DAY_OF_MONTH, -1);
            cal.add(Calendar.DAY_OF_MONTH, 30);
            Date currentDate = df.parse(df.format(cal.getTime())); // cal.getTime()

            String ruleSql = "select f.house_id as houseId, r.charge_type as chargeType,r.start_time AS startTime,r.end_time AS endTime,r.close_time AS closeTime,"
                    + " r.expense_id AS expenseId,r.flag ,r.day ,r.create_time AS createTime ,r.id,r.date_flag AS dateFlag,r.collection_org as collectionOrg   "
                    + " from saas_house_expense_rule_ref f left join saas_house_expense_bill_rule r "
                    + "on f.rule_id = r.id where r.charge_type in(1, 2, 3, 4, 5, 6, 7) and r.type = 1  ";  // type :1公租房 2非公租房

            // 查询账单生成规则数据
            List<Map<String, Object>> ruleList = jdbcTemplate.queryForList(ruleSql);
            if (CollectionUtils.isEmpty(ruleList)) {
                log.info(" 没有其它费用账单规则数据  end");
                return;
            }

            // 收费项目id集合
            List<String> expenseId = new ArrayList<>();
            // 公租房id集合
            List<String> hIds = new ArrayList<>();

            for (Map<String, Object> k : ruleList) {
                hIds.add(k.get("houseId").toString());
                expenseId.add(k.get("expenseId").toString());
            }

            hIds = hIds.stream().distinct().collect(Collectors.toList());

            // 查询收费项目
            List<HouseExpenseOther> projectList = houseExpenseOtherRepository.findByIdIn(expenseId);
            if (projectList.size() == 0) {
                log.info(" 没有收费项目数据  end");
                return;
            }

            // 收费项目
            Map<String, List<HouseExpenseOther>> projectMap = projectList.stream().collect(Collectors.groupingBy(HouseExpenseOther::getId));
            // 公租房信息
            List<House> houseList = houseRepository.findByIdIn(hIds);
            // 公租房信息Map
            Map<String, List<House>> houseMap = houseList.stream().collect(Collectors.groupingBy(House::getId));
            // 账单生成规则信息
            Map<String, List<Map<String, Object>>> ruleMap = ruleList.stream().collect(Collectors.groupingBy((Map<String, Object> m) -> m.get("houseId") + "_" + m.get("chargeType")));

            // houseId_chargeType
            for (String houseIdStr : ruleMap.keySet()) {

                String hct[] = houseIdStr.split("_");
                String houseId = hct[0];
                Integer chargeType = Integer.parseInt(hct[1]);

                // 规则信息
                List<Map<String, Object>> rList = ruleMap.get(houseIdStr);
                if (CollectionUtils.isEmpty(rList)) {
                    log.warn("未找到规则信息  houseId={}", houseIdStr);
                    continue;
                }
                // 可能存在多个周期
                for (Map<String, Object> rMap : rList) {
                    // 公租房信息
                    List<House> hList = houseMap.get(houseId);
                    if (CollectionUtils.isEmpty(hList)) {
                        log.warn("未找到公租房信息 houseId={}", houseId);
                        continue;
                    }
                    House house = hList.get(0);
                    Integer flag = (Integer) rMap.get("flag");
                    Integer day = (Integer) rMap.get("day");
                    Object dateFlagObj = rMap.get("dateFlag");
                    // 收款单位
                    Long collectionOrg = (Long) rMap.get("collectionOrg");

                    // 规则生成时间
                    Calendar calen = Calendar.getInstance();
                    calen.setTime((Date) rMap.get("createTime"));
                    calen.add(Calendar.DAY_OF_MONTH, 30);
                    String createTime = df.format(calen.getTime());
                    String rid = (String) rMap.get("id");
                    Date startDate = df.parse(df.format((Date) rMap.get("startTime")));
                    Date endDate = df.parse(df.format((Date) rMap.get("endTime")));
                    // 收费项目
                    List<HouseExpenseOther> otherList = projectMap.get((String) rMap.get("expenseId"));
                    if (otherList == null) {
                        log.warn("找不到收费项目，v={}", (String) rMap.get("expenseId"));
                        continue;
                    }
                    HouseExpenseOther other = otherList.get(0);
                    Integer chargeMode = other.getChargeMode();

                    // 只生成当前时间在时间周期内的账单
                    if (currentDate.getTime() >= startDate.getTime() && currentDate.getTime() <= endDate.getTime()) {
                        // 拆分时间段
                        List<Map<String, String>> dateList = new ArrayList<>();
                        Date tempDate = startDate;
                        BigDecimal month = new BigDecimal(1);
                        switch (chargeMode) {
                            case 1:
                                dateList = dateList(tempDate, endDate, 1);
                                month = new BigDecimal(1);
                                break;
                            case 2:
                                dateList = dateList(tempDate, endDate, 3);
                                month = new BigDecimal(3);
                                break;
                            case 3:
                                dateList = dateList(tempDate, endDate, 6);
                                month = new BigDecimal(6);
                                break;
                            case 4:
                                dateList = dateList(tempDate, endDate, 12);
                                month = new BigDecimal(12);
                                break;
                        }

                        String cDate = df.format(currentDate);

                        // 规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                        Boolean flags = false;
                        if (cDate.equals(createTime)) {
                            flags = true;
                        }
                        for (Map<String, String> m : dateList) {
                            String start = m.get("start");
                            String end = m.get("end");
                            // 获取截止时间
                            Date startTimes = df.parse(start);

                            if (dateFlagObj != null) {
                                Integer dateFlag = (Integer) dateFlagObj; // 时间标志：1开始时间 2结束时间
                                if (dateFlag.equals(2)) {
                                    startTimes = df.parse(end);
                                }
                            }

                            Date closeTime = null;
                            if (flag.equals(1)) {  // 1前 2后
                                Calendar c = Calendar.getInstance();
                                c.setTime(startTimes);
                                c.add(Calendar.DAY_OF_MONTH, -day);
                                closeTime = c.getTime();
                            } else {
                                Calendar c = Calendar.getInstance();
                                c.setTime(startTimes);
                                c.add(Calendar.DAY_OF_MONTH, day);
                                closeTime = c.getTime();
                            }

                            //(当前时间 == 开始时间) 或者 (规则生成时间 == 当前时间和开始时间 < 当前时间)
                            if (cDate.equals(start) || (flags && df.parse(start).getTime() < currentDate.getTime())) {
                                // 按对应方式生成账单

                                // int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                                // 价格:单位分
                                Integer cose = 0;
                                BigDecimal price = new BigDecimal(other.getPrice());
                                // 计量单位，如：月/度/平方
                                String unit = other.getUnit();
                                BigDecimal temp = null;
                                switch ((Integer) rMap.get("chargeType")) {  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                    case 3:
                                        // 物业费 = 面积 * 单价 * 天数
                                        BigDecimal area = house.getArea();
                                        temp = area.multiply(price).multiply(month);
                                        cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 4:
                                        // 宽带费 = 月份 * 单价
                                        temp = month.multiply(price);
                                        cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 5:
                                        // 电视费 = 月份 * 单价
                                        temp = month.multiply(price);
                                        cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 7:
                                        // 暖气费 = 面积 * 单价 * 日期
                                        BigDecimal area1 = house.getArea();
                                        temp = area1.multiply(price).multiply(month);
                                        cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                }

                                List<String> hlist = new ArrayList<>();
                                hlist.add(houseId);
                                List<HouseMatchUser> hmUserList = houseMatchUserRepository.findByHouseIdInAndStatus(hlist, 1);
                                String matchUserId = null;
                                if (hmUserList.size() > 0) {
                                    matchUserId = hmUserList.get(0).getMatchUserId();
                                }

                                // 生成账单
                                ExpenseBill expenseBill = new ExpenseBill();

                                expenseBill.setHouseId(houseId);
                                expenseBill.setChargeType(chargeType);
                                expenseBill.setCommunityId(house.getResidenceCommunityId());
                                expenseBill.setBuildingNum(house.getBuildingNum());
                                expenseBill.setUnit(house.getUnit());
                                if (collectionOrg == null) {
                                    expenseBill.setOrgId(house.getOrgId());
                                } else {
                                    expenseBill.setOrgId(collectionOrg);
                                }
                                expenseBill.setPaymentStatus(0);
                                expenseBill.setRoomNumber(house.getRoomNumber());
                                expenseBill.setMatchUserId(matchUserId);
                                expenseBill.setCost(cose);
                                expenseBill.setMeasureUnit(unit);
                                expenseBill.setStartTime(df.parse(start));
                                expenseBill.setEndTime(df.parse(end));
                                expenseBill.setShouldPayTime(closeTime);
                                expenseBill.setCreateTime(new Date());
                                expenseBill.setAuditStatus(0);     // 审核状态：0未审核 1已审核
                                expenseBill.setBillType(1);
                                expenseBill.setRuleId(rid);

                                ExpenseBill save = expenseBillRepository.save(expenseBill);

                                // 公租房合同与其它费用账单关系表 saas_expense_bill_relation
                                ExpenseBillRelation relation = new ExpenseBillRelation();
                                relation.setHouseId(expenseBill.getHouseId());
                                relation.setExpenseBillId(expenseBill.getId());
                                relation.setMatchUserId(expenseBill.getMatchUserId());
                                // relation.setContractNubmer(houseContract.getContractNubmer());

                                expenseBillRelationRepository.save(relation);

                                HouseWaitPaymentDetail houseWaitPaymentDetail = new HouseWaitPaymentDetail();
                                houseWaitPaymentDetail.setExpenseBillId(save.getId());
                                houseWaitPaymentDetail.setChargeType(save.getChargeType());
                                switch (save.getChargeType()) {   // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                    case 1:
                                        houseWaitPaymentDetail.setWaterStartNum(0);
                                        houseWaitPaymentDetail.setWaterEndNum(0);
                                        houseWaitPaymentDetail.setWaterUsage(0.0);
                                        houseWaitPaymentDetail.setWaterUnitPrice(Integer.valueOf(price.toString()));

                                        break;
                                    case 2:
                                        houseWaitPaymentDetail.setElectricStartNum(0);
                                        houseWaitPaymentDetail.setElectricEndNum(0);
                                        houseWaitPaymentDetail.setElectricUsage(0.0);
                                        houseWaitPaymentDetail.setElectricUnitPrice(Integer.valueOf(price.toString()));
                                        break;
                                    case 3:
                                        houseWaitPaymentDetail.setPropertyFee(save.getCost());
                                        break;
                                    case 4:
                                        houseWaitPaymentDetail.setBroadBandCharges(save.getCost());
                                        break;
                                    case 5:
                                        houseWaitPaymentDetail.setTvFee(save.getCost());
                                        break;
                                    case 6:
                                        houseWaitPaymentDetail.setGasStartNum(0);
                                        houseWaitPaymentDetail.setGasEndNum(0);
                                        houseWaitPaymentDetail.setGasUsage(0.0);
                                        houseWaitPaymentDetail.setGasUnitPrice(Integer.valueOf(price.toString()));
                                        break;
                                    case 7:
                                        houseWaitPaymentDetail.setHeatingBill(save.getCost());
                                        break;
                                }

                                houseWaitPaymentDetailRepository.save(houseWaitPaymentDetail);

                            }
                        }

                    } else {
                        // 当前时间不在时间周期内的账单
                        // 整个周期账单小于当前时间
                        if (currentDate.getTime() > startDate.getTime() && currentDate.getTime() > endDate.getTime()) {
                            // 规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                            String curr = df.format(currentDate);
                            if (curr.equals(createTime)) {
                                // 拆分时间段
                                List<Map<String, String>> dateList = new ArrayList<>();
                                Date tempDate = startDate;
                                BigDecimal month = new BigDecimal(1);
                                switch (chargeMode) {
                                    case 1:
                                        dateList = dateList(tempDate, endDate, 1);
                                        month = new BigDecimal(1);
                                        break;
                                    case 2:
                                        dateList = dateList(tempDate, endDate, 3);
                                        month = new BigDecimal(3);
                                        break;
                                    case 3:
                                        dateList = dateList(tempDate, endDate, 6);
                                        month = new BigDecimal(6);
                                        break;
                                    case 4:
                                        dateList = dateList(tempDate, endDate, 12);
                                        month = new BigDecimal(12);
                                        break;
                                }

                                for (Map<String, String> m : dateList) {
                                    // 按对应方式生成账单
                                    String start = m.get("start");
                                    String end = m.get("end");

                                    // 获取截止时间
                                    Date startTimes = df.parse(start);

                                    if (dateFlagObj != null) {
                                        Integer dateFlag = (Integer) dateFlagObj; // 时间标志：1开始时间 2结束时间
                                        if (dateFlag.equals(2)) {
                                            startTimes = df.parse(end);
                                        }
                                    }

                                    Date closeTime = null;
                                    if (flag.equals(1)) {  // 1前 2后
                                        Calendar c = Calendar.getInstance();
                                        c.setTime(startTimes);
                                        c.add(Calendar.DAY_OF_MONTH, -day);
                                        closeTime = c.getTime();
                                    } else {
                                        Calendar c = Calendar.getInstance();
                                        c.setTime(startTimes);
                                        c.add(Calendar.DAY_OF_MONTH, day);
                                        closeTime = c.getTime();
                                    }


                                    // int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                                    // 价格:单位分
                                    Integer cose = 0;
                                    BigDecimal price = new BigDecimal(other.getPrice());
                                    // 计量单位，如：月/度/平方
                                    String unit = other.getUnit();
                                    BigDecimal temp = null;
                                    switch ((Integer) rMap.get("chargeType")) {  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                        case 3:
                                            // 物业费 = 面积 * 单价 * 天数
                                            BigDecimal area = house.getArea();
                                            temp = area.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 4:
                                            // 宽带费 = 月份 * 单价
                                            temp = month.multiply(price);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 5:
                                            // 电视费 = 月份 * 单价
                                            temp = month.multiply(price);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 7:
                                            // 暖气费 = 面积 * 单价 * 日期
                                            BigDecimal area1 = house.getArea();
                                            temp = area1.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                    }

                                    List<String> hlist = new ArrayList<>();
                                    hlist.add(houseId);
                                    List<HouseMatchUser> hmUserList = houseMatchUserRepository.findByHouseIdInAndStatus(hlist, 1);
                                    String matchUserId = null;
                                    if (hmUserList.size() > 0) {
                                        matchUserId = hmUserList.get(0).getMatchUserId();
                                    }

                                    // 生成账单
                                    ExpenseBill expenseBill = new ExpenseBill();

                                    expenseBill.setHouseId(houseId);
                                    expenseBill.setChargeType(chargeType);
                                    expenseBill.setCommunityId(house.getResidenceCommunityId());
                                    expenseBill.setBuildingNum(house.getBuildingNum());
                                    expenseBill.setUnit(house.getUnit());
                                    if (collectionOrg == null) {
                                        expenseBill.setOrgId(house.getOrgId());
                                    } else {
                                        expenseBill.setOrgId(collectionOrg);
                                    }
                                    expenseBill.setPaymentStatus(0);
                                    expenseBill.setRoomNumber(house.getRoomNumber());
                                    expenseBill.setMatchUserId(matchUserId);
                                    expenseBill.setCost(cose);
                                    expenseBill.setMeasureUnit(unit);
                                    expenseBill.setStartTime(df.parse(start));
                                    expenseBill.setEndTime(df.parse(end));
                                    expenseBill.setShouldPayTime(closeTime);
                                    expenseBill.setCreateTime(new Date());
                                    expenseBill.setAuditStatus(0);     // 审核状态：0未审核 1已审核
                                    expenseBill.setBillType(1);
                                    expenseBill.setRuleId(rid);

                                    ExpenseBill save = expenseBillRepository.save(expenseBill);

                                    // 公租房合同与其它费用账单关系表 saas_expense_bill_relation
                                    ExpenseBillRelation relation = new ExpenseBillRelation();
                                    relation.setHouseId(expenseBill.getHouseId());
                                    relation.setExpenseBillId(expenseBill.getId());
                                    relation.setMatchUserId(expenseBill.getMatchUserId());
                                    // relation.setContractNubmer(houseContract.getContractNubmer());

                                    expenseBillRelationRepository.save(relation);

                                    HouseWaitPaymentDetail houseWaitPaymentDetail = new HouseWaitPaymentDetail();
                                    houseWaitPaymentDetail.setExpenseBillId(save.getId());
                                    houseWaitPaymentDetail.setChargeType(save.getChargeType());
                                    switch (save.getChargeType()) {   // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                        case 1:
                                            houseWaitPaymentDetail.setWaterStartNum(0);
                                            houseWaitPaymentDetail.setWaterEndNum(0);
                                            houseWaitPaymentDetail.setWaterUsage(0.0);
                                            houseWaitPaymentDetail.setWaterUnitPrice(Integer.valueOf(price.toString()));

                                            break;
                                        case 2:
                                            houseWaitPaymentDetail.setElectricStartNum(0);
                                            houseWaitPaymentDetail.setElectricEndNum(0);
                                            houseWaitPaymentDetail.setElectricUsage(0.0);
                                            houseWaitPaymentDetail.setElectricUnitPrice(Integer.valueOf(price.toString()));
                                            break;
                                        case 3:
                                            houseWaitPaymentDetail.setPropertyFee(save.getCost());
                                            break;
                                        case 4:
                                            houseWaitPaymentDetail.setBroadBandCharges(save.getCost());
                                            break;
                                        case 5:
                                            houseWaitPaymentDetail.setTvFee(save.getCost());
                                            break;
                                        case 6:
                                            houseWaitPaymentDetail.setGasStartNum(0);
                                            houseWaitPaymentDetail.setGasEndNum(0);
                                            houseWaitPaymentDetail.setGasUsage(0.0);
                                            houseWaitPaymentDetail.setGasUnitPrice(Integer.valueOf(price.toString()));
                                            break;
                                        case 7:
                                            houseWaitPaymentDetail.setHeatingBill(save.getCost());
                                            break;
                                    }

                                    houseWaitPaymentDetailRepository.save(houseWaitPaymentDetail);
                                }

                            }

                        }

                    }

                }

            }

            log.info("生成其它费用账单明细   end");

        } catch (Exception e) {
            log.error("生成其它费用账单明细异常  " + e.getMessage(), e);
        }
    }

    // 物业房产账单-生成租金/押金账单
    public void propertyRentBill() throws Exception {
        try {
            log.info(" 生成租金/押金账单明细  start");

            // 当前时间 [凌晨2点跑前一天的数据]
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            Calendar cal = Calendar.getInstance();
            cal.setTime(new Date());
            cal.add(Calendar.DAY_OF_MONTH, -1);
            cal.add(Calendar.DAY_OF_MONTH, 30);
            Date currentDate = df.parse(df.format(cal.getTime())); // cal.getTime()

            String ruleSql = "select f.house_id as houseId, r.charge_type as chargeType,r.start_time AS startTime,r.end_time AS endTime,r.close_time AS closeTime,"
                    + " r.expense_id AS expenseId,r.flag ,r.day ,r.create_time AS createTime ,r.id,r.date_flag AS dateFlag,r.collection_org as collectionOrg ,f.audit_status as auditStatus  "
                    + " from saas_house_expense_rule_ref f left join saas_house_expense_bill_rule r "
                    + "on f.rule_id = r.id where r.charge_type in(8,9) and f.house_nature != 1 and r.status = 0  and f.audit_status IN (0,1) and r.create_status != 1 ";

            // 查询账单生成规则数据
            List<Map<String, Object>> ruleList = jdbcTemplate.queryForList(ruleSql);
            if (CollectionUtils.isEmpty(ruleList)) {
                log.info(" 没有租金/押金账单规则数据  end");
                return;
            }

            // 收费项目id集合
            List<String> expenseId = new ArrayList<>();
            // 公租房id集合
            List<String> hIds = new ArrayList<>();

            for (Map<String, Object> k : ruleList) {
                hIds.add(k.get("houseId").toString());
                expenseId.add(k.get("expenseId").toString());
            }

            hIds = hIds.stream().distinct().collect(Collectors.toList());

            // 查询收费项目
            List<HouseExpenseOther> projectList = houseExpenseOtherRepository.findByIdIn(expenseId);
            if (projectList.size() == 0) {
                log.info(" 没有收费项目数据  end");
                return;
            }

            // 收费项目
            Map<String, List<HouseExpenseOther>> projectMap = projectList.stream().collect(Collectors.groupingBy(HouseExpenseOther::getId));
            // 公租房信息
            List<House> houseList = houseRepository.findByIdIn(hIds);
            // 公租房信息Map
            Map<String, List<House>> houseMap = houseList.stream().collect(Collectors.groupingBy(House::getId));
            // 账单生成规则信息
            Map<String, List<Map<String, Object>>> ruleMap = ruleList.stream().collect(Collectors.groupingBy((Map<String, Object> m) -> m.get("houseId") + "_" + m.get("chargeType")));

            // houseId_chargeType
            for (String houseIdStr : ruleMap.keySet()) {

                String hct[] = houseIdStr.split("_");
                String houseId = hct[0];
                Integer chargeType = Integer.parseInt(hct[1]);

                // 规则信息
                List<Map<String, Object>> rList = ruleMap.get(houseIdStr);
                if (CollectionUtils.isEmpty(rList)) {
                    log.warn("未找到规则信息  houseId={}", houseIdStr);
                    continue;
                }

                // 可能存在多个周期
                for (Map<String, Object> rMap : rList) {
                    // 公租房信息
                    List<House> hList = houseMap.get(houseId);
                    if (CollectionUtils.isEmpty(hList)) {
                        log.warn("未找到公租房信息 houseId={}", houseId);
                        continue;
                    }
                    House house = hList.get(0);
                    Integer flag = (Integer) rMap.get("flag");
                    Integer day = (Integer) rMap.get("day");
                    Object dateFlagObj = rMap.get("dateFlag");
                    // 收款单位
                    Long collectionOrg = (Long) rMap.get("collectionOrg");

                    // 规则生成时间
                    Calendar calen = Calendar.getInstance();
                    calen.setTime((Date) rMap.get("createTime"));
                    calen.add(Calendar.DAY_OF_MONTH, 30);
                    String createTime = df.format(calen.getTime());
                    String rid = (String) rMap.get("id");
                    Date startDate = df.parse(df.format((Date) rMap.get("startTime")));
                    Date endDate = df.parse(df.format((Date) rMap.get("endTime")));
                    // 收费项目
                    List<HouseExpenseOther> otherList = projectMap.get((String) rMap.get("expenseId"));
                    if (otherList == null) {
                        log.warn("找不到收费项目，v={}", (String) rMap.get("expenseId"));
                        continue;
                    }
                    HouseExpenseOther other = otherList.get(0);
                    Integer chargeMode = other.getChargeMode();

                    // 只生成当前时间在时间周期内的账单
                    if (currentDate.getTime() >= startDate.getTime() && currentDate.getTime() <= endDate.getTime()) {
                        // 拆分时间段
                        List<Map<String, String>> dateList = new ArrayList<>();
                        Date tempDate = startDate;
                        BigDecimal month = new BigDecimal(1);
                        if (chargeMode != null) {
                            switch (chargeMode) {
                                case 1:
                                    dateList = dateList(tempDate, endDate, 1);
                                    month = new BigDecimal(1);
                                    break;
                                case 2:
                                    dateList = dateList(tempDate, endDate, 3);
                                    month = new BigDecimal(3);
                                    break;
                                case 3:
                                    dateList = dateList(tempDate, endDate, 6);
                                    month = new BigDecimal(6);
                                    break;
                                case 4:
                                    dateList = dateList(tempDate, endDate, 12);
                                    month = new BigDecimal(12);
                                    break;
                            }
                        } else {
                            Map<String, String> map = new HashMap<>();
                            map.put("start", df.format(tempDate));
                            map.put("end", df.format(endDate));
                            dateList.add(map);
                        }

                        String cDate = df.format(currentDate);

                        // 规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                        Boolean flags = false;
                        if (cDate.equals(createTime)) {
                            flags = true;
                        }

                        for (Map<String, String> m : dateList) {
                            String start = m.get("start");
                            String end = m.get("end");

                            // 获取截止时间
                            Date startTimes = df.parse(start);

                            if (dateFlagObj != null) {
                                Integer dateFlag = (Integer) dateFlagObj; // 时间标志：1开始时间 2结束时间
                                if (dateFlag.equals(2)) {
                                    startTimes = df.parse(end);
                                }
                            }

                            Date closeTime = null;
                            if (flag.equals(1)) {  // 1前 2后
                                Calendar c = Calendar.getInstance();
                                c.setTime(startTimes);
                                c.add(Calendar.DAY_OF_MONTH, -day);
                                c.set(Calendar.HOUR_OF_DAY, 23);
                                c.set(Calendar.MINUTE, 59);
                                c.set(Calendar.SECOND, 59);
                                // 防止mysql自动加一秒,毫秒设为0
                                c.set(Calendar.MILLISECOND, 0);
                                closeTime = c.getTime();
                            } else {
                                Calendar c = Calendar.getInstance();
                                c.setTime(startTimes);
                                c.add(Calendar.DAY_OF_MONTH, day);
                                c.set(Calendar.HOUR_OF_DAY, 23);
                                c.set(Calendar.MINUTE, 59);
                                c.set(Calendar.SECOND, 59);
                                // 防止mysql自动加一秒,毫秒设为0
                                c.set(Calendar.MILLISECOND, 0);
                                closeTime = c.getTime();
                            }

                            //(当前时间 == 开始时间) 或者 (规则生成时间 == 当前时间和开始时间 < 当前时间)
                            if (cDate.equals(start) || (flags && df.parse(start).getTime() < currentDate.getTime())) {
                                // 按对应方式生成账单

                                // int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                                // 价格:单位分
                                Integer cose = 0;
                                BigDecimal price = new BigDecimal(other.getPrice());
                                // 计量单位，如：月/度/平方
                                String unit = other.getUnit();
                                BigDecimal temp = null;
                                switch ((Integer) rMap.get("chargeType")) {  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                    case 3:
                                        // 物业费 = 面积 * 单价 * 天数
                                        BigDecimal area = house.getArea();
                                        temp = area.multiply(price).multiply(month);
                                        cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 4:
                                        // 宽带费 = 月份 * 单价
                                        temp = month.multiply(price);
                                        cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 5:
                                        // 电视费 = 月份 * 单价
                                        temp = month.multiply(price);
                                        cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 7:
                                        // 暖气费 = 面积 * 单价 * 日期
                                        BigDecimal area1 = house.getArea();
                                        temp = area1.multiply(price).multiply(month);
                                        cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 8:
                                        // 租金  单价 = 面积 * 单价 * 天数
                                        if (other.getChargeStatus() == 0) {
                                            BigDecimal area2 = house.getArea();
                                            temp = area2.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        } else {
                                            // 总价 价格 * 天数
                                            temp = price.multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        }
                                        break;
                                    case 9:
                                        // 押金 = 单价(一次性)
                                        temp = price;
                                        cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                }

                                // List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseId, 1, 1);
                                // String matchUserId = null;
                                // if (communityHouseUserList.size() > 0) {
                                //     matchUserId = communityHouseUserList.get(0).getUserId();
                                // }

                                String matchUserId = null;
                                List<MatchUserHouse> byHouseId = matchUserHouseRepository.findByHouseId(houseId);
                                if (!byHouseId.isEmpty()) {
                                    String matchUserStockId = byHouseId.get(0).getMatchUserStockId();
                                    //	根据承租人和房产的承租人id查询承认人表的房产承租人id
                                    Optional<MatchUser> matchUserRepositoryById = matchUserRepository.findById(Long.parseLong(matchUserStockId));
                                    if (matchUserRepositoryById.isPresent()) {
                                        // 产权下的用户承租人id
                                        MatchUser byMatchUserId = matchUserRepositoryById.get();
                                        // 产权下的用户承租人id
                                        matchUserId = byMatchUserId.getMatchUserId();
                                    }
                                }
                                // 收费项目:8租金 9押金
                                Integer billChargeType = 2;
                                if (chargeType == 8) {
                                    billChargeType = 1;
                                }

                                // 生成账单
                                EstateRentBill estateRentBill = new EstateRentBill();
                                estateRentBill.setHouseId(houseId);
                                estateRentBill.setChargeType(billChargeType);
                                estateRentBill.setCommunityId(house.getResidenceCommunityId());
                                estateRentBill.setBuildingNum(house.getBuildingNum());
                                estateRentBill.setUnit(house.getUnit());
                                if (collectionOrg == null) {
                                    estateRentBill.setOrgId(house.getHousePropertyId());
                                } else {
                                    estateRentBill.setOrgId(collectionOrg);
                                }
                                estateRentBill.setPaymentStatus(0);
                                estateRentBill.setRoomNumber(house.getRoomNumber());
                                estateRentBill.setMatchUserId(matchUserId);
                                estateRentBill.setCost(cose);
                                estateRentBill.setSurplusCost(cose);
                                estateRentBill.setMeasureUnit(unit);
                                estateRentBill.setStartTime(df.parse(start));
                                estateRentBill.setEndTime(df.parse(end));
                                estateRentBill.setShouldPayTime(closeTime);
                                estateRentBill.setCreateTime(new Date());
                                estateRentBill.setBillType(1);
                                estateRentBill.setAuditStatus(0);     // 审核状态：0未审核 1已审核
                                estateRentBill.setRuleId(rid);
                                estateRentBill.setAdjustStatus(0);
                                EstateRentBill save = estateRentBillRepository.save(estateRentBill);

                                Integer auditStatus = (Integer) rMap.get("auditStatus");
                                // 除首次生成账单及需要设置用量的账单外，账单生成后自动审核通过扣费
                                if (1 == auditStatus && !(chargeType == 1 || chargeType == 2 || chargeType == 6)) {
                                    Boolean depStatus = false;
                                    DepartmentRemainingRef depRef = new DepartmentRemainingRef();
                                    Long unitLesseeId = house.getUnitLesseeId();
                                    if (unitLesseeId != null) {
                                        depRef = departmentRemainingRefRepository.findByDepIdAndHouseIdAndOrgId(unitLesseeId, houseId, save.getOrgId());
                                        // 租金押金代扣开启状态 : 0是 1否
                                        if (depRef != null) {
                                            if (depRef.getRentWithholdStatus() == 0) {
                                                depStatus = true;
                                            }
                                        }
                                    }
                                    if (depStatus) {
                                        Long remainingId = depRef.getRemainingId();
                                        Integer status = deductionDepartmentRemaining(remainingId, save.getId(), chargeType);
                                        save = estateRentBillRepository.findById(save.getId()).get();
                                        // 余额不够扣减账单 自动审核通过
                                        if (status != DeductionEnum.ALL_PAY.getValue()) {
                                            payEstateRentBillItem(houseId, save.getId(), save.getChargeType(), save.getCost(), redisService.getSystemUser(), save);
                                        }
                                    } else {
                                        HouseRemainingRelation rel = houseRemainingRelationRepository.findByOrgIdAndHouseId(collectionOrg, houseId);
                                        if (null != rel) {
                                            Integer status = deductionRemaining(rel.getRemainingId(), save.getId(), chargeType);
                                            save = estateRentBillRepository.findById(save.getId()).get();
                                            // 余额不够扣减账单 自动审核通过
                                            if (status != DeductionEnum.ALL_PAY.getValue()) {
                                                payEstateRentBillItem(houseId, save.getId(), save.getChargeType(), save.getCost(), redisService.getSystemUser(), save);
                                            }
                                        }
                                    }
                                    save.setAuditStatus(1);
                                    estateRentBillRepository.save(save);
                                }
                            }
                        }

                        Optional<HouseExpenseBillRule> byId = houseExpenseBillRuleRepository.findById(rid);
                        if (byId.isPresent()) {
                            HouseExpenseBillRule houseExpenseBillRule = byId.get();
                            houseExpenseBillRule.setCreateStatus(1);
                            houseExpenseBillRuleRepository.save(houseExpenseBillRule);
                        }
                    } else {
                        // 当前时间不在时间周期内的账单
                        // 整个周期账单小于当前时间
                        if (currentDate.getTime() > startDate.getTime() && currentDate.getTime() > endDate.getTime()) {
                            // 规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                            String curr = df.format(currentDate);
                            if (curr.equals(createTime)) {
                                // 拆分时间段
                                List<Map<String, String>> dateList = new ArrayList<>();
                                Date tempDate = startDate;
                                BigDecimal month = new BigDecimal(1);
                                if (null != chargeMode) {
                                    switch (chargeMode) {
                                        case 1:
                                            dateList = dateList(tempDate, endDate, 1);
                                            month = new BigDecimal(1);
                                            break;
                                        case 2:
                                            dateList = dateList(tempDate, endDate, 3);
                                            month = new BigDecimal(3);
                                            break;
                                        case 3:
                                            dateList = dateList(tempDate, endDate, 6);
                                            month = new BigDecimal(6);
                                            break;
                                        case 4:
                                            dateList = dateList(tempDate, endDate, 12);
                                            month = new BigDecimal(12);
                                            break;
                                    }
                                } else {
                                    Map<String, String> map = new HashMap<>();
                                    map.put("start", df.format(tempDate));
                                    map.put("end", df.format(endDate));
                                    dateList.add(map);
                                }


                                for (Map<String, String> m : dateList) {
                                    // 按对应方式生成账单
                                    String start = m.get("start");
                                    String end = m.get("end");

                                    // 获取截止时间
                                    Date startTimes = df.parse(start);

                                    if (dateFlagObj != null) {
                                        Integer dateFlag = (Integer) dateFlagObj; // 时间标志：1开始时间 2结束时间
                                        if (dateFlag.equals(2)) {
                                            startTimes = df.parse(end);
                                        }
                                    }

                                    Date closeTime = null;
                                    if (flag.equals(1)) {  // 1前 2后
                                        Calendar c = Calendar.getInstance();
                                        c.setTime(startTimes);
                                        c.add(Calendar.DAY_OF_MONTH, -day);
                                        c.set(Calendar.HOUR_OF_DAY, 23);
                                        c.set(Calendar.MINUTE, 59);
                                        c.set(Calendar.SECOND, 59);
                                        // 防止mysql自动加一秒,毫秒设为0
                                        c.set(Calendar.MILLISECOND, 0);
                                        closeTime = c.getTime();
                                    } else {
                                        Calendar c = Calendar.getInstance();
                                        c.setTime(startTimes);
                                        c.add(Calendar.DAY_OF_MONTH, day);
                                        c.set(Calendar.HOUR_OF_DAY, 23);
                                        c.set(Calendar.MINUTE, 59);
                                        c.set(Calendar.SECOND, 59);
                                        // 防止mysql自动加一秒,毫秒设为0
                                        c.set(Calendar.MILLISECOND, 0);
                                        closeTime = c.getTime();
                                    }


                                    // int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                                    // 价格:单位分
                                    Integer cose = 0;
                                    BigDecimal price = new BigDecimal(other.getPrice());
                                    // 计量单位，如：月/度/平方
                                    String unit = other.getUnit();
                                    BigDecimal temp = null;
                                    switch ((Integer) rMap.get("chargeType")) {  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                        case 3:
                                            // 物业费 = 面积 * 单价 * 天数
                                            BigDecimal area = house.getArea();
                                            temp = area.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 4:
                                            // 宽带费 = 月份 * 单价
                                            temp = month.multiply(price);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 5:
                                            // 电视费 = 月份 * 单价
                                            temp = month.multiply(price);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 7:
                                            // 暖气费 = 面积 * 单价 * 日期
                                            BigDecimal area1 = house.getArea();
                                            temp = area1.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 8:
                                            // 租金 = 面积 * 单价 * 天数
                                            BigDecimal area2 = house.getArea();
                                            temp = area2.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 9:
                                            // 押金 = 单价(一次性)
                                            temp = price;
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                    }

                                    /*List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseId, 1, 1);
                                    String matchUserId = null;
                                    if (communityHouseUserList.size() > 0) {
                                        matchUserId = communityHouseUserList.get(0).getUserId();
                                    }*/

                                    String matchUserId = null;
                                    List<MatchUserHouse> byHouseId = matchUserHouseRepository.findByHouseId(houseId);
                                    if (!byHouseId.isEmpty()) {
                                        String matchUserStockId = byHouseId.get(0).getMatchUserStockId();
                                        //	根据承租人和房产的承租人id查询承认人表的房产承租人id
                                        Optional<MatchUser> matchUserRepositoryById = matchUserRepository.findById(Long.parseLong(matchUserStockId));
                                        if (matchUserRepositoryById.isPresent()) {
                                            // 产权下的用户承租人id
                                            MatchUser byMatchUserId = matchUserRepositoryById.get();
                                            // 产权下的用户承租人id
                                            matchUserId = byMatchUserId.getMatchUserId();
                                        }
                                    }

                                    // 收费项目:8租金 9押金
                                    Integer billChargeType = 2;
                                    if (chargeType == 8) {
                                        billChargeType = 1;
                                    }

                                    // 生成账单
                                    EstateRentBill estateRentBill = new EstateRentBill();
                                    estateRentBill.setHouseId(houseId);
                                    estateRentBill.setChargeType(billChargeType);
                                    estateRentBill.setCommunityId(house.getResidenceCommunityId());
                                    estateRentBill.setBuildingNum(house.getBuildingNum());
                                    estateRentBill.setUnit(house.getUnit());
                                    if (collectionOrg == null) {
                                        estateRentBill.setOrgId(house.getHousePropertyId());
                                    } else {
                                        estateRentBill.setOrgId(collectionOrg);
                                    }
                                    estateRentBill.setPaymentStatus(0);
                                    estateRentBill.setRoomNumber(house.getRoomNumber());
                                    estateRentBill.setMatchUserId(matchUserId);
                                    estateRentBill.setCost(cose);
                                    estateRentBill.setSurplusCost(cose);
                                    estateRentBill.setMeasureUnit(unit);
                                    estateRentBill.setStartTime(df.parse(start));
                                    estateRentBill.setEndTime(df.parse(end));
                                    estateRentBill.setShouldPayTime(closeTime);
                                    estateRentBill.setCreateTime(new Date());
                                    estateRentBill.setBillType(1);
                                    estateRentBill.setAuditStatus(0);     // 审核状态：0未审核 1已审核
                                    estateRentBill.setRuleId(rid);
                                    estateRentBill.setAdjustStatus(0);
                                    EstateRentBill save = estateRentBillRepository.save(estateRentBill);

                                    Integer auditStatus = (Integer) rMap.get("auditStatus");
                                    // 除首次生成账单及需要设置用量的账单外，账单生成后自动审核通过扣费
                                    if (1 == auditStatus && !(chargeType == 1 || chargeType == 2 || chargeType == 7)) {
                                        Boolean depStatus = false;
                                        DepartmentRemainingRef depRef = new DepartmentRemainingRef();
                                        Long unitLesseeId = house.getUnitLesseeId();
                                        if (unitLesseeId != null) {
                                            depRef = departmentRemainingRefRepository.findByDepIdAndHouseIdAndOrgId(unitLesseeId, houseId, save.getOrgId());
                                            // 租金押金代扣开启状态 : 0是 1否
                                            if (depRef != null) {
                                                if (depRef.getRentWithholdStatus() == 0) {
                                                    depStatus = true;
                                                }
                                            }
                                        }
                                        if (depStatus) {
                                            Long remainingId = depRef.getRemainingId();
                                            Integer status = deductionDepartmentRemaining(remainingId, save.getId(), chargeType);
                                            save = estateRentBillRepository.findById(save.getId()).get();
                                            // 余额不够扣减账单 自动审核通过
                                            if (status != DeductionEnum.ALL_PAY.getValue()) {
                                                payEstateRentBillItem(houseId, save.getId(), save.getChargeType(), save.getCost(), redisService.getSystemUser(), save);
                                            }
                                        } else {
                                            HouseRemainingRelation rel = houseRemainingRelationRepository.findByOrgIdAndHouseId(collectionOrg, houseId);
                                            if (null != rel) {
                                                Integer status = deductionRemaining(rel.getRemainingId(), save.getId(), chargeType);
                                                save = estateRentBillRepository.findById(save.getId()).get();
                                                // 余额不够扣减账单 自动审核通过
                                                if (status != DeductionEnum.ALL_PAY.getValue()) {
                                                    payEstateRentBillItem(houseId, save.getId(), save.getChargeType(), save.getCost(), redisService.getSystemUser(), save);
                                                }
                                            }
                                        }
                                        save.setAuditStatus(1);
                                        estateRentBillRepository.save(save);
                                    }

                                }
                                Optional<HouseExpenseBillRule> byId = houseExpenseBillRuleRepository.findById(rid);
                                if (byId.isPresent()) {
                                    HouseExpenseBillRule houseExpenseBillRule = byId.get();
                                    houseExpenseBillRule.setCreateStatus(1);
                                    houseExpenseBillRuleRepository.save(houseExpenseBillRule);
                                }
                            }

                        }

                    }


                }

            }

            log.info(" 生成租金/押金账单明细  end");

        } catch (Exception e) {
            log.error("生成租金/押金账单明细异常  " + e.getMessage(), e);
        }
    }

    // 物业房产账单-其它费用账单
    public void propertyOtherBill() throws Exception {
        try {
            log.info(" 物业房产账单-其它费用账单 生成其它费用账单明细  start");

            // 当前时间 [凌晨2点跑前一天的数据]
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            Calendar cal = Calendar.getInstance();
            cal.setTime(new Date());
            cal.add(Calendar.DAY_OF_MONTH, -1);
            cal.add(Calendar.DAY_OF_MONTH, 30);
            Date currentDate = df.parse(df.format(cal.getTime())); // cal.getTime()

            String ruleSql = "select f.house_id as houseId, r.charge_type as chargeType,r.start_time AS startTime,r.end_time AS endTime,r.close_time AS closeTime,"
                    + " r.expense_id AS expenseId,r.flag ,r.day ,r.create_time AS createTime ,r.id , f.house_nature AS houseNature,"
                    + "r.date_flag AS dateFlag,r.collection_org as collectionOrg,f.audit_status as auditStatus "
                    + " from saas_house_expense_rule_ref f left join saas_house_expense_bill_rule r "
                    + "on f.rule_id = r.id where r.charge_type in(1, 2, 3, 4, 5, 6, 7) and r.type = 2 and r.status = 0 and f.audit_status IN (0,1) and r.create_status != 1 "; // type :1公租房 2非公租房[包含公租房]

            // 查询账单生成规则数据
            List<Map<String, Object>> ruleList = jdbcTemplate.queryForList(ruleSql);
            if (CollectionUtils.isEmpty(ruleList)) {
                log.info(" 没有其它费用账单规则数据  end");
                return;
            }

            // 收费项目id集合
            List<String> expenseId = new ArrayList<>();
            // 公租房id集合
            List<String> hIds = new ArrayList<>();

            for (Map<String, Object> k : ruleList) {
                hIds.add(k.get("houseId").toString());
                expenseId.add(k.get("expenseId").toString());
            }

            hIds = hIds.stream().distinct().collect(Collectors.toList());

            // 查询收费项目
            List<HouseExpenseOther> projectList = houseExpenseOtherRepository.findByIdIn(expenseId);
            if (projectList.size() == 0) {
                log.info(" 没有收费项目数据  end");
                return;
            }

            // 收费项目
            Map<String, List<HouseExpenseOther>> projectMap = projectList.stream().collect(Collectors.groupingBy(HouseExpenseOther::getId));
            // 公租房信息
            List<House> houseList = houseRepository.findByIdIn(hIds);
            // 公租房信息Map
            Map<String, List<House>> houseMap = houseList.stream().collect(Collectors.groupingBy(House::getId));
            // 账单生成规则信息
            Map<String, List<Map<String, Object>>> ruleMap = ruleList.stream().collect(Collectors.groupingBy((Map<String, Object> m) -> m.get("houseId") + "_" + m.get("chargeType")));

            // houseId_chargeType
            for (String houseIdStr : ruleMap.keySet()) {

                String hct[] = houseIdStr.split("_");
                String houseId = hct[0];
                // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8租金 9押金
                Integer chargeType = Integer.parseInt(hct[1]);

                // 规则信息
                List<Map<String, Object>> rList = ruleMap.get(houseIdStr);
                if (CollectionUtils.isEmpty(rList)) {
                    log.warn("未找到规则信息  houseId={}", houseIdStr);
                    continue;
                }

                // 可能存在多个周期
                for (Map<String, Object> rMap : rList) {
                    // 公租房信息
                    List<House> hList = houseMap.get(houseId);
                    if (CollectionUtils.isEmpty(hList)) {
                        log.warn("未找到公租房信息 houseId={}", houseId);
                        continue;
                    }
                    House house = hList.get(0);
                    Integer flag = (Integer) rMap.get("flag");
                    Integer day = (Integer) rMap.get("day");
                    Integer houseNature = (Integer) rMap.get("houseNature");
                    Object dateFlagObj = rMap.get("dateFlag");
                    // 收款单位
                    Long collectionOrg = (Long) rMap.get("collectionOrg");

                    // 规则生成时间
                    Calendar calen = Calendar.getInstance();
                    calen.setTime((Date) rMap.get("createTime"));
                    calen.add(Calendar.DAY_OF_MONTH, 30);
                    String createTime = df.format(calen.getTime());
                    String rid = (String) rMap.get("id");
                    Date startDate = df.parse(df.format((Date) rMap.get("startTime")));
                    Date endDate = df.parse(df.format((Date) rMap.get("endTime")));
                    // 收费项目
                    List<HouseExpenseOther> otherList = projectMap.get((String) rMap.get("expenseId"));
                    if (otherList == null) {
                        log.warn("找不到收费项目，v={}", (String) rMap.get("expenseId"));
                        continue;
                    }
                    HouseExpenseOther other = otherList.get(0);
                    Integer chargeMode = other.getChargeMode();

                    // 只生成当前时间在时间周期内的账单
                    if (currentDate.getTime() >= startDate.getTime() && currentDate.getTime() <= endDate.getTime()) {
                        // 拆分时间段
                        List<Map<String, String>> dateList = new ArrayList<>();
                        Date tempDate = startDate;
                        BigDecimal month = new BigDecimal(1);
                        switch (chargeMode) {
                            case 1:
                                dateList = dateList(tempDate, endDate, 1);
                                month = new BigDecimal(1);
                                break;
                            case 2:
                                dateList = dateList(tempDate, endDate, 3);
                                month = new BigDecimal(3);
                                break;
                            case 3:
                                dateList = dateList(tempDate, endDate, 6);
                                month = new BigDecimal(6);
                                break;
                            case 4:
                                dateList = dateList(tempDate, endDate, 12);
                                month = new BigDecimal(12);
                                break;
                        }

                        String cDate = df.format(currentDate);

                        // 规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                        Boolean flags = false;
                        if (cDate.equals(createTime)) {
                            flags = true;
                        }

                        for (Map<String, String> m : dateList) {
                            String start = m.get("start");
                            String end = m.get("end");

                            // 获取截止时间
                            Date startTimes = df.parse(start);

                            if (dateFlagObj != null) {
                                Integer dateFlag = (Integer) dateFlagObj; // 时间标志：1开始时间 2结束时间
                                if (dateFlag.equals(2)) {
                                    startTimes = df.parse(end);
                                }
                            }


                            Date closeTime = null;
                            if (flag.equals(1)) {  // 1前 2后
                                Calendar c = Calendar.getInstance();
                                c.setTime(startTimes);
                                c.add(Calendar.DAY_OF_MONTH, -day);
                                c.set(Calendar.HOUR_OF_DAY, 23);
                                c.set(Calendar.MINUTE, 59);
                                c.set(Calendar.SECOND, 59);
                                // 防止mysql自动加一秒,毫秒设为0
                                c.set(Calendar.MILLISECOND, 0);
                                closeTime = c.getTime();
                                // System.out.println("closeTime = " + closeTime);
                            } else {
                                Calendar c = Calendar.getInstance();
                                c.setTime(startTimes);
                                c.add(Calendar.DAY_OF_MONTH, day);
                                c.set(Calendar.HOUR_OF_DAY, 23);
                                c.set(Calendar.MINUTE, 59);
                                c.set(Calendar.SECOND, 59);
                                // 防止mysql自动加一秒,毫秒设为0
                                c.set(Calendar.MILLISECOND, 0);
                                closeTime = c.getTime();
                                // System.out.println("closeTime = " + closeTime);
                            }

                            //(当前时间 == 开始时间) 或者 (规则生成时间 == 当前时间和开始时间 < 当前时间)
                            if (cDate.equals(start) || (flags && df.parse(start).getTime() < currentDate.getTime())) {
                                // 按对应方式生成账单

                                // int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                                // 价格:单位分
                                Integer cose = 0;
                                BigDecimal price = new BigDecimal(other.getPrice());
                                // 计量单位，如：月/度/平方
                                String unit = other.getUnit();
                                BigDecimal temp = null;
                                switch ((Integer) rMap.get("chargeType")) {  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                    case 3:
                                        // 物业费 = 面积 * 单价 * 天数
                                        BigDecimal area = house.getArea();
                                        temp = area.multiply(price).multiply(month);
                                        cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 4:
                                        // 宽带费 = 月份 * 单价
                                        temp = month.multiply(price);
                                        cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 5:
                                        // 电视费 = 月份 * 单价
                                        temp = month.multiply(price);
                                        cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 7:
                                        // 暖气费 = 面积 * 单价 * 日期
                                        BigDecimal area1 = house.getArea();
                                        temp = area1.multiply(price).multiply(month);
                                        cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                }

                                String matchUserId = null;
                                List<MatchUserHouse> byHouseId = matchUserHouseRepository.findByHouseId(houseId);
                                if (!byHouseId.isEmpty()) {
                                    String matchUserStockId = byHouseId.get(0).getMatchUserStockId();
                                    //	根据承租人和房产的承租人id查询承认人表的房产承租人id
                                    Optional<MatchUser> matchUserRepositoryById = matchUserRepository.findById(Long.parseLong(matchUserStockId));
                                    if (matchUserRepositoryById.isPresent()) {
                                        // 产权下的用户承租人id
                                        MatchUser byMatchUserId = matchUserRepositoryById.get();
                                        // 产权下的用户承租人id
                                        matchUserId = byMatchUserId.getMatchUserId();
                                    }
                                }

                                /*else {
                                    List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseId, 1, 1);
                                    if (communityHouseUserList.size() > 0) {
                                        matchUserId = communityHouseUserList.get(0).getUserId();
                                    }

                                    if (houseNature != null && houseNature.equals(1)) {  // 公租房
                                        List<String> hlist = new ArrayList<>();
                                        hlist.add(houseId);
                                        List<HouseMatchUser> hmUserList = houseMatchUserRepository.findByHouseIdInAndStatus(hlist, 1);
                                        if (hmUserList.size() > 0) {
                                            matchUserId = hmUserList.get(0).getMatchUserId();
                                        }
                                    }
                                }*/


                                // 生成账单
                                EstateExpenseBill estateExpenseBill = new EstateExpenseBill();

                                estateExpenseBill.setHouseId(houseId);
                                estateExpenseBill.setChargeType(chargeType);
                                estateExpenseBill.setCommunityId(house.getResidenceCommunityId());
                                estateExpenseBill.setBuildingNum(house.getBuildingNum());
                                estateExpenseBill.setUnit(house.getUnit());
                                if (collectionOrg == null) {
                                    estateExpenseBill.setOrgId(house.getHousePropertyId());
                                } else {
                                    estateExpenseBill.setOrgId(collectionOrg);
                                }
                                estateExpenseBill.setPaymentStatus(0);
                                estateExpenseBill.setRoomNumber(house.getRoomNumber());
                                estateExpenseBill.setMatchUserId(matchUserId);
                                estateExpenseBill.setCost(cose);
                                estateExpenseBill.setSurplusCost(cose);
                                estateExpenseBill.setMeasureUnit(unit);
                                estateExpenseBill.setStartTime(df.parse(start));
                                estateExpenseBill.setEndTime(df.parse(end));
                                estateExpenseBill.setCreateTime(new Date());
                                estateExpenseBill.setAuditStatus(0);      //'审核状态：0未审核 1已审核'
                                estateExpenseBill.setBillType(1);
                                estateExpenseBill.setShouldPayTime(closeTime);
                                estateExpenseBill.setRuleId(rid);
                                estateExpenseBill.setAdjustStatus(0);
                                EstateExpenseBill save = estateExpenseBillRepository.save(estateExpenseBill);
                                Integer auditStatus = (Integer) rMap.get("auditStatus");
                                // 除首次生成账单及需要设置用量的账单外，账单生成后自动审核通过扣费
                                if (1 == auditStatus && !(chargeType == 1 || chargeType == 2 || chargeType == 6)) {
                                    // 单位承租人是否关联扣减账单
                                    Boolean depStatus = false;
                                    DepartmentRemainingRef depRef = new DepartmentRemainingRef();
                                    Long unitLesseeId = house.getUnitLesseeId();
                                    if (unitLesseeId != null) {
                                        if (depRef != null) {
                                            depRef = departmentRemainingRefRepository.findByDepIdAndHouseIdAndOrgId(unitLesseeId, houseId, save.getOrgId());
                                            // 其他费用代扣开启状态 : 0是 1否
                                            if (depRef.getElseWithholdStatus() == 0) {
                                                depStatus = true;
                                            }
                                        }
                                    }
                                    if (depStatus) {
                                        Long remainingId = depRef.getRemainingId();
                                        Integer status = deductionDepartmentRemaining(remainingId, save.getId(), chargeType);
                                        save = estateExpenseBillRepository.findById(save.getId()).get();
                                        // 余额不够扣减账单 自动审核通过
                                        if (status != DeductionEnum.ALL_PAY.getValue()) {
                                            payEstateExpenseBillItem(houseId, save.getId(), save.getChargeType(), save.getCost(), redisService.getSystemUser(), save);
                                        }
                                    } else {
                                        HouseRemainingRelation rel = houseRemainingRelationRepository.findByOrgIdAndHouseId(collectionOrg, houseId);
                                        if (null != rel) {
                                            Integer status = deductionRemaining(rel.getRemainingId(), save.getId(), chargeType);
                                            save = estateExpenseBillRepository.findById(save.getId()).get();
                                            // 余额不够扣减账单 自动审核通过
                                            if (status != DeductionEnum.ALL_PAY.getValue()) {
                                                payEstateExpenseBillItem(houseId, save.getId(), save.getChargeType(), save.getCost(), redisService.getSystemUser(), save);
                                            }
                                        }
                                    }
                                    save.setAuditStatus(1);
                                    estateExpenseBillRepository.save(save);
                                }

                                EstateExpenseBillDetail estateExpenseBillDetail = new EstateExpenseBillDetail();
                                List<EstateExpenseBill> andHouseId = estateExpenseBillRepository.findByRuleIdAndHouseIdAndChargeType(rid, houseId, chargeType);
                                if (!andHouseId.isEmpty()) {
                                    if (andHouseId.size() >= 2) {
                                        // 获取上个账单起止数
                                        estateExpenseBillDetail = estateExpenseBillDetailRepository.findByExpenseBillId(andHouseId.get(andHouseId.size() - 2).getId());
                                    } else {
                                        // 获取上个账单起止数
                                        estateExpenseBillDetail = estateExpenseBillDetailRepository.findByExpenseBillId(andHouseId.get(0).getId());
                                    }
                                }
                                if (andHouseId.size() <= 1 && estateExpenseBillDetail == null) {
                                    EstateExpenseBillDetail detail = new EstateExpenseBillDetail();
                                    detail.setExpenseBillId(save.getId());
                                    detail.setChargeType(save.getChargeType());
                                    switch (save.getChargeType()) {   // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                        case 1:
                                            detail.setWaterStartNum(0);
                                            detail.setWaterEndNum(0);
                                            detail.setWaterUsage(null);
                                            detail.setWaterUnitPrice(Integer.valueOf(price.toString()));
                                            break;
                                        case 2:
                                            detail.setElectricStartNum(0);
                                            detail.setElectricEndNum(0);
                                            detail.setElectricUsage(null);
                                            detail.setElectricUnitPrice(Integer.valueOf(price.toString()));
                                            break;
                                        case 3:
                                            detail.setPropertyFee(save.getCost());
                                            break;
                                        case 4:
                                            detail.setBroadBandCharges(save.getCost());
                                            break;
                                        case 5:
                                            detail.setTvFee(save.getCost());
                                            break;
                                        case 6:
                                            detail.setGasStartNum(0);
                                            detail.setGasEndNum(0);
                                            detail.setGasUsage(null);
                                            detail.setGasUnitPrice(Integer.valueOf(price.toString()));
                                            break;
                                        case 7:
                                            detail.setHeatingBill(save.getCost());
                                            break;
                                    }

                                    estateExpenseBillDetailRepository.save(detail);
                                }
                                if (!andHouseId.isEmpty() && estateExpenseBillDetail != null) {

                                    EstateExpenseBillDetail estateExpenseBill1 = new EstateExpenseBillDetail();
                                    estateExpenseBill1.setExpenseBillId(save.getId());
                                    estateExpenseBill1.setChargeType(save.getChargeType());
                                    switch (save.getChargeType()) {   // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                        case 1:
                                            estateExpenseBill1.setWaterStartNum(estateExpenseBillDetail.getWaterEndNum());
                                            estateExpenseBill1.setWaterEndNum(0);
                                            estateExpenseBill1.setWaterUsage(null);
                                            estateExpenseBill1.setWaterUnitPrice(Integer.valueOf(price.toString()));

                                            break;
                                        case 2:
                                            estateExpenseBill1.setElectricStartNum(estateExpenseBillDetail.getElectricEndNum());
                                            estateExpenseBill1.setElectricEndNum(0);
                                            estateExpenseBill1.setElectricUsage(null);
                                            estateExpenseBill1.setElectricUnitPrice(Integer.valueOf(price.toString()));
                                            break;
                                        case 3:
                                            estateExpenseBill1.setPropertyFee(save.getCost());
                                            break;
                                        case 4:
                                            estateExpenseBill1.setBroadBandCharges(save.getCost());
                                            break;
                                        case 5:
                                            estateExpenseBill1.setTvFee(save.getCost());
                                            break;
                                        case 6:
                                            estateExpenseBill1.setGasStartNum(estateExpenseBillDetail.getGasEndNum());
                                            estateExpenseBill1.setGasEndNum(0);
                                            estateExpenseBill1.setGasUsage(null);
                                            estateExpenseBill1.setGasUnitPrice(Integer.valueOf(price.toString()));
                                            break;
                                        case 7:
                                            estateExpenseBill1.setHeatingBill(save.getCost());
                                            break;
                                    }

                                    estateExpenseBillDetailRepository.save(estateExpenseBill1);
                                }


                            }
                        }
                        Optional<HouseExpenseBillRule> byId = houseExpenseBillRuleRepository.findById(rid);
                        if (byId.isPresent()) {
                            HouseExpenseBillRule houseExpenseBillRule = byId.get();
                            houseExpenseBillRule.setCreateStatus(1);
                            houseExpenseBillRuleRepository.save(houseExpenseBillRule);
                        }
                    } else {
                        // 当前时间不在时间周期内的账单
                        // 整个周期账单小于当前时间
                        if (currentDate.getTime() > startDate.getTime() && currentDate.getTime() > endDate.getTime()) {
                            // 规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                            String curr = df.format(currentDate);
                            if (curr.equals(createTime)) {
                                // 拆分时间段
                                List<Map<String, String>> dateList = new ArrayList<>();
                                Date tempDate = startDate;
                                BigDecimal month = new BigDecimal(1);
                                switch (chargeMode) {
                                    case 1:
                                        dateList = dateList(tempDate, endDate, 1);
                                        month = new BigDecimal(1);
                                        break;
                                    case 2:
                                        dateList = dateList(tempDate, endDate, 3);
                                        month = new BigDecimal(3);
                                        break;
                                    case 3:
                                        dateList = dateList(tempDate, endDate, 6);
                                        month = new BigDecimal(6);
                                        break;
                                    case 4:
                                        dateList = dateList(tempDate, endDate, 12);
                                        month = new BigDecimal(12);
                                        break;
                                }

                                for (Map<String, String> m : dateList) {
                                    // 按对应方式生成账单
                                    String start = m.get("start");
                                    String end = m.get("end");

                                    // 获取截止时间
                                    Date startTimes = df.parse(start);

                                    if (dateFlagObj != null) {
                                        Integer dateFlag = (Integer) dateFlagObj; // 时间标志：1开始时间 2结束时间
                                        if (dateFlag.equals(2)) {
                                            startTimes = df.parse(end);
                                        }
                                    }

                                    Date closeTime = null;
                                    if (flag.equals(1)) {  // 1前 2后
                                        Calendar c = Calendar.getInstance();
                                        c.setTime(startTimes);
                                        c.add(Calendar.DAY_OF_MONTH, -day);
                                        c.set(Calendar.HOUR_OF_DAY, 23);
                                        c.set(Calendar.MINUTE, 59);
                                        c.set(Calendar.SECOND, 59);
                                        // 防止mysql自动加一秒,毫秒设为0
                                        c.set(Calendar.MILLISECOND, 0);
                                        closeTime = c.getTime();
                                        System.out.println("closeTime = " + closeTime);
                                    } else {
                                        Calendar c = Calendar.getInstance();
                                        c.setTime(startTimes);
                                        c.add(Calendar.DAY_OF_MONTH, day);
                                        c.set(Calendar.HOUR_OF_DAY, 23);
                                        c.set(Calendar.MINUTE, 59);
                                        c.set(Calendar.SECOND, 59);
                                        // 防止mysql自动加一秒,毫秒设为0
                                        c.set(Calendar.MILLISECOND, 0);
                                        closeTime = c.getTime();
                                        System.out.println("closeTime = " + closeTime);
                                    }


                                    // int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                                    // 价格:单位分
                                    Integer cose = 0;
                                    BigDecimal price = new BigDecimal(other.getPrice());
                                    // 计量单位，如：月/度/平方
                                    String unit = other.getUnit();
                                    BigDecimal temp = null;
                                    switch ((Integer) rMap.get("chargeType")) {  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                        case 3:
                                            // 物业费 = 面积 * 单价 * 天数
                                            BigDecimal area = house.getArea();
                                            temp = area.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 4:
                                            // 宽带费 = 月份 * 单价
                                            temp = month.multiply(price);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 5:
                                            // 电视费 = 月份 * 单价
                                            temp = month.multiply(price);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 7:
                                            // 暖气费 = 面积 * 单价 * 日期
                                            BigDecimal area1 = house.getArea();
                                            temp = area1.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                    }

                                    // List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseId, 1, 1);
                                    // String matchUserId = null;
                                    // if (communityHouseUserList.size() > 0) {
                                    //     matchUserId = communityHouseUserList.get(0).getUserId();
                                    // }

                                    String matchUserId = null;
                                    List<MatchUserHouse> byHouseId = matchUserHouseRepository.findByHouseId(houseId);
                                    if (!byHouseId.isEmpty()) {
                                        String matchUserStockId = byHouseId.get(0).getMatchUserStockId();
                                        //	根据承租人和房产的承租人id查询承认人表的房产承租人id
                                        Optional<MatchUser> matchUserRepositoryById = matchUserRepository.findById(Long.parseLong(matchUserStockId));
                                        if (matchUserRepositoryById.isPresent()) {
                                            // 产权下的用户承租人id
                                            MatchUser byMatchUserId = matchUserRepositoryById.get();
                                            // 产权下的用户承租人id
                                            matchUserId = byMatchUserId.getMatchUserId();
                                        }
                                    }

                                    // 生成账单
                                    EstateExpenseBill estateExpenseBill = new EstateExpenseBill();

                                    estateExpenseBill.setHouseId(houseId);
                                    estateExpenseBill.setChargeType(chargeType);
                                    estateExpenseBill.setCommunityId(house.getResidenceCommunityId());
                                    estateExpenseBill.setBuildingNum(house.getBuildingNum());
                                    estateExpenseBill.setUnit(house.getUnit());
                                    if (collectionOrg == null) {
                                        estateExpenseBill.setOrgId(house.getHousePropertyId());
                                    } else {
                                        estateExpenseBill.setOrgId(collectionOrg);
                                    }
                                    estateExpenseBill.setPaymentStatus(0);
                                    estateExpenseBill.setRoomNumber(house.getRoomNumber());
                                    estateExpenseBill.setMatchUserId(matchUserId);
                                    estateExpenseBill.setCost(cose);
                                    estateExpenseBill.setSurplusCost(cose);
                                    estateExpenseBill.setMeasureUnit(unit);
                                    estateExpenseBill.setStartTime(df.parse(start));
                                    estateExpenseBill.setEndTime(df.parse(end));
                                    estateExpenseBill.setCreateTime(new Date());
                                    estateExpenseBill.setAuditStatus(0);      //'审核状态：0未审核 1已审核'
                                    estateExpenseBill.setBillType(1);
                                    estateExpenseBill.setShouldPayTime(closeTime);
                                    estateExpenseBill.setRuleId(rid);
                                    estateExpenseBill.setAdjustStatus(0);
                                    EstateExpenseBill save = estateExpenseBillRepository.save(estateExpenseBill);
                                    Integer auditStatus = (Integer) rMap.get("auditStatus");
                                    // 除首次生成账单及需要设置用量的账单外，账单生成后自动审核通过扣费
                                    if (1 == auditStatus && !(chargeType == 1 || chargeType == 2 || chargeType == 6)) {
                                        // 单位承租人是否关联扣减账单
                                        boolean depStatus = false;
                                        DepartmentRemainingRef depRef = new DepartmentRemainingRef();
                                        Long unitLesseeId = house.getUnitLesseeId();
                                        if (unitLesseeId != null) {
                                            depRef = departmentRemainingRefRepository.findByDepIdAndHouseIdAndOrgId(unitLesseeId, houseId, save.getOrgId());
                                            // 其他费用代扣开启状态 : 0是 1否
                                            if (depRef != null) {
                                                if (depRef.getElseWithholdStatus() == 0) {
                                                    depStatus = true;
                                                }
                                            }
                                        }
                                        if (depStatus) {
                                            Long remainingId = depRef.getRemainingId();
                                            Integer status = deductionDepartmentRemaining(remainingId, save.getId(), chargeType);
                                            save = estateExpenseBillRepository.findById(save.getId()).get();
                                            // 余额不够扣减账单 自动审核通过
                                            if (status != DeductionEnum.ALL_PAY.getValue()) {
                                                payEstateExpenseBillItem(houseId, save.getId(), save.getChargeType(), save.getCost(), redisService.getSystemUser(), save);
                                            }
                                        } else {
                                            HouseRemainingRelation rel = houseRemainingRelationRepository.findByOrgIdAndHouseId(collectionOrg, houseId);
                                            if (null != rel) {
                                                Integer status = deductionRemaining(rel.getRemainingId(), save.getId(), chargeType);
                                                save = estateExpenseBillRepository.findById(save.getId()).get();
                                                // 余额不够扣减账单 自动审核通过
                                                if (status != DeductionEnum.ALL_PAY.getValue()) {
                                                    payEstateExpenseBillItem(houseId, save.getId(), save.getChargeType(), save.getCost(), redisService.getSystemUser(), save);
                                                }
                                            }
                                        }
                                        save.setAuditStatus(1);
                                        estateExpenseBillRepository.save(save);
                                    }

                                    // 其他费用账单用量
                                    EstateExpenseBillDetail estateExpenseBillDetail = new EstateExpenseBillDetail();
                                    List<EstateExpenseBill> andHouseId = estateExpenseBillRepository.findByRuleIdAndHouseIdAndChargeType(rid, houseId, chargeType);
                                    if (!andHouseId.isEmpty()) {
                                        if (andHouseId.size() > 2) {
                                            // 获取上个账单起止数
                                            estateExpenseBillDetail = estateExpenseBillDetailRepository.findByExpenseBillId(andHouseId.get(andHouseId.size() - 2).getId());
                                        } else {
                                            // 获取上个账单起止数
                                            estateExpenseBillDetail = estateExpenseBillDetailRepository.findByExpenseBillId(andHouseId.get(0).getId());
                                        }
                                    }
                                    if (andHouseId.size() == 1 && estateExpenseBillDetail == null) {
                                        EstateExpenseBillDetail detail = new EstateExpenseBillDetail();
                                        detail.setExpenseBillId(save.getId());
                                        detail.setChargeType(save.getChargeType());
                                        switch (save.getChargeType()) {   // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                            case 1:
                                                detail.setWaterStartNum(0);
                                                detail.setWaterEndNum(0);
                                                detail.setWaterUsage(null);
                                                detail.setWaterUnitPrice(Integer.valueOf(price.toString()));
                                                break;
                                            case 2:
                                                detail.setElectricStartNum(0);
                                                detail.setElectricEndNum(0);
                                                detail.setElectricUsage(null);
                                                detail.setElectricUnitPrice(Integer.valueOf(price.toString()));
                                                break;
                                            case 3:
                                                detail.setPropertyFee(save.getCost());
                                                break;
                                            case 4:
                                                detail.setBroadBandCharges(save.getCost());
                                                break;
                                            case 5:
                                                detail.setTvFee(save.getCost());
                                                break;
                                            case 6:
                                                detail.setGasStartNum(0);
                                                detail.setGasEndNum(0);
                                                detail.setGasUsage(null);
                                                detail.setGasUnitPrice(Integer.valueOf(price.toString()));
                                                break;
                                            case 7:
                                                detail.setHeatingBill(save.getCost());
                                                break;
                                        }

                                        estateExpenseBillDetailRepository.save(detail);
                                    }
                                    if (!andHouseId.isEmpty() && estateExpenseBillDetail != null) {

                                        EstateExpenseBillDetail estateExpenseBill1 = new EstateExpenseBillDetail();
                                        estateExpenseBill1.setExpenseBillId(save.getId());
                                        estateExpenseBill1.setChargeType(save.getChargeType());
                                        switch (save.getChargeType()) {   // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                            case 1:
                                                estateExpenseBill1.setWaterStartNum(estateExpenseBillDetail.getWaterEndNum());
                                                estateExpenseBill1.setWaterEndNum(0);
                                                estateExpenseBill1.setWaterUsage(null);
                                                estateExpenseBill1.setWaterUnitPrice(Integer.valueOf(price.toString()));

                                                break;
                                            case 2:
                                                estateExpenseBill1.setElectricStartNum(estateExpenseBillDetail.getElectricEndNum());
                                                estateExpenseBill1.setElectricEndNum(0);
                                                estateExpenseBill1.setElectricUsage(null);
                                                estateExpenseBill1.setElectricUnitPrice(Integer.valueOf(price.toString()));
                                                break;
                                            case 3:
                                                estateExpenseBill1.setPropertyFee(save.getCost());
                                                break;
                                            case 4:
                                                estateExpenseBill1.setBroadBandCharges(save.getCost());
                                                break;
                                            case 5:
                                                estateExpenseBill1.setTvFee(save.getCost());
                                                break;
                                            case 6:
                                                estateExpenseBill1.setGasStartNum(estateExpenseBillDetail.getGasEndNum());
                                                estateExpenseBill1.setGasEndNum(0);
                                                estateExpenseBill1.setGasUsage(null);
                                                estateExpenseBill1.setGasUnitPrice(Integer.valueOf(price.toString()));
                                                break;
                                            case 7:
                                                estateExpenseBill1.setHeatingBill(save.getCost());
                                                break;
                                        }

                                        estateExpenseBillDetailRepository.save(estateExpenseBill1);
                                    }


                                }
                                Optional<HouseExpenseBillRule> byId = houseExpenseBillRuleRepository.findById(rid);
                                if (byId.isPresent()) {
                                    HouseExpenseBillRule houseExpenseBillRule = byId.get();
                                    houseExpenseBillRule.setCreateStatus(1);
                                    houseExpenseBillRuleRepository.save(houseExpenseBillRule);
                                }
                            }

                        }

                    }
                }
            }
            log.info(" 生成其它费用账单明细   end");

        } catch (Exception e) {
            log.error("生成其它费用账单明细异常  " + e.getMessage(), e);
        }
    }

    /**
     * 余额扣减账单
     * 对应账单优先扣减设置类型的账单 余额自动扣减账单 余额账户非延期状态冻结智能锁 判断是否生成违约金 违约金按剩余费用比例生成
     */
    public void remainingDeductionBill() {
        try {
            log.info("余额扣减账单 remainingDeductionBill() 扣减账单 start");

            // 物业其他账单
            List<EstateExpenseBill> expenseBillList = estateExpenseBillRepository.findByAuditStatusAndPaymentStatus(1, 0, 2);
            // 物业租金押金
            List<EstateRentBill> rentBillList = estateRentBillRepository.findByAuditStatusAndPaymentStatus(1, 0, 2);

            // 获取对应机构账单设置 优先扣款账单
            List<Long> orgList = new ArrayList<>();
            orgList.addAll(expenseBillList.stream().map(EstateExpenseBill::getOrgId).distinct().collect(Collectors.toList()));
            orgList.addAll(rentBillList.stream().map(EstateRentBill::getOrgId).distinct().collect(Collectors.toList()));
            List<DepartmentBill> departmentBillList = departmentBillRepository.findByDepIdIn(orgList);
            departmentBillList = departmentBillList.stream().filter(e -> e.getSmartLockStatus() != null && e.getBillStatus() != null).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(departmentBillList)) {
                for (DepartmentBill departmentBill : departmentBillList) {
                    // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8租金  9押金 10退租

                    Integer billStatus = departmentBill.getBillStatus();
                    if (billStatus != null) {
                        switch (billStatus) {
                            // 1水费
                            case 1:
                            case 2:
                            case 3:
                            case 4:
                            case 5:
                            case 6:
                            case 7:
                                List<EstateExpenseBill> bills = expenseBillList.stream().filter(e -> e.getOrgId().equals(departmentBill.getDepId()) && e.getChargeType().equals(billStatus)).collect(Collectors.toList());
                                // 处理完成缴费的账单
                                List<EstateExpenseBill> payBillList = deductionExpenseBill(bills, billStatus);
                                expenseBillList.removeAll(payBillList);
                                break;
                      /*  //2电费
                        case 2:
                            List<EstateExpenseBill> bills1 = expenseBillList.stream().filter(e -> e.getChargeType() == billStatus && e.getOrgId() == departmentBill.getDepId()).collect(Collectors.toList());
                            //处理完成缴费的账单
                            List<EstateExpenseBill> payBillList1 = deductionExpenseBill(bills1, billStatus);
                            expenseBillList.removeAll(payBillList1);
                            break;
                        //3物业费
                        case 3:
                            List<EstateExpenseBill> bills2 = expenseBillList.stream().filter(e -> e.getChargeType() == billStatus && e.getOrgId() == departmentBill.getDepId()).collect(Collectors.toList());
                            //处理完成缴费的账单
                            List<EstateExpenseBill> payBillList2 = deductionExpenseBill(bills2, billStatus);
                            expenseBillList.removeAll(payBillList2);
                            break;
                        //4宽带费
                        case 4:
                            List<EstateExpenseBill> bills3 = expenseBillList.stream().filter(e -> e.getChargeType() == billStatus && e.getOrgId() == departmentBill.getDepId()).collect(Collectors.toList());
                            //处理完成缴费的账单
                            List<EstateExpenseBill> payBillList3 = deductionExpenseBill(bills3, billStatus);
                            expenseBillList.removeAll(payBillList3);
                            break;
                        //5电视费
                        case 5:
                            List<EstateExpenseBill> bills4 = expenseBillList.stream().filter(e -> e.getChargeType() == billStatus && e.getOrgId() == departmentBill.getDepId()).collect(Collectors.toList());
                            //处理完成缴费的账单
                            List<EstateExpenseBill> payBillList4 = deductionExpenseBill(bills4, billStatus);
                            expenseBillList.removeAll(payBillList4);
                            break;
                        //6煤气费
                        case 6:
                            List<EstateExpenseBill> bills5 = expenseBillList.stream().filter(e -> e.getChargeType() == billStatus && e.getOrgId() == departmentBill.getDepId()).collect(Collectors.toList());
                            //处理完成缴费的账单
                            List<EstateExpenseBill> payBillList5 = deductionExpenseBill(bills5, billStatus);
                            expenseBillList.removeAll(payBillList5);
                            break;
                        //7暖气费
                        case 7:
                            List<EstateExpenseBill> bills6 = expenseBillList.stream().filter(e -> e.getChargeType() == billStatus && e.getOrgId() == departmentBill.getDepId()).collect(Collectors.toList());
                            //处理完成缴费的账单
                            List<EstateExpenseBill> payBillList6 = deductionExpenseBill(bills6, billStatus);
                            expenseBillList.removeAll(payBillList6);
                            break;*/
                            case 8:
                            case 9:
                                List<EstateRentBill> bills7 = rentBillList.stream().filter(e -> e.getOrgId().equals(departmentBill.getDepId()) && (e.getChargeType() == 1 ? 8 : 9) == billStatus).collect(Collectors.toList());
                                // 处理完成缴费的账单
                                List<EstateRentBill> payBillList7 = deductionRentBill(bills7, billStatus);
                                rentBillList.removeAll(payBillList7);
                                break;
                           /* List<EstateRentBill> bills8 = rentBillList.stream().filter(e -> e.getChargeType() == billStatus && e.getOrgId() == departmentBill.getDepId()).collect(Collectors.toList());
                            //处理完成缴费的账单
                            List<EstateRentBill> payBillList8 = deductionRentBill(bills8, billStatus);
                            rentBillList.removeAll(payBillList8);
                            break;*/
                            case 10:
                                break;
                        }
                    }
                }
            }

            Long orgId = 0L;
            String houseId = "";
            Integer chargeType = 0;
            Long currentTime = new Date().getTime();
            // 其他费用
            for (EstateExpenseBill estateExpenseBill : expenseBillList) {
                Integer flag = null;
                chargeType = estateExpenseBill.getChargeType();
                orgId = estateExpenseBill.getOrgId();
                houseId = estateExpenseBill.getHouseId();

                Optional<House> byId1 = houseRepository.findById(houseId);
                House house = byId1.get();

                HouseRemainingRelation rel = houseRemainingRelationRepository.findByOrgIdAndHouseId(orgId, houseId);
                if (rel == null) {
                    log.warn("未找到账单对应余额账户  " + estateExpenseBill.getId());
                    continue;
                }
                Optional<HouseRemaining> remaining = houseRemainingRepository.findById(rel.getRemainingId());
                if (!remaining.isPresent()) {
                    log.warn("未找到账单对应余额账户  " + estateExpenseBill.getId());
                    continue;
                }
                HouseRemaining houseRemaining = remaining.get();
                // 状态：1正常 2已删除 3延期 4欠费
                Integer remStatus = houseRemaining.getStatus();
                try {
                    // 单位承租人是否关联扣减账单
                    Boolean depStatus = false;
                    DepartmentRemainingRef depRef = new DepartmentRemainingRef();
                    Long unitLesseeId = house.getUnitLesseeId();
                    if (unitLesseeId != null) {
                        depRef = departmentRemainingRefRepository.findByDepIdAndHouseIdAndOrgId(unitLesseeId, houseId, orgId);
                        // 其他费用代扣开启状态 : 0是 1否
                        if (depRef != null) {
                            if (depRef.getElseWithholdStatus() != null) {
                                if (depRef.getElseWithholdStatus() == 0) {
                                    depStatus = true;
                                }
                            }
                        }
                    }
                    if (depStatus) {
                        Long remainingId = depRef.getRemainingId();
                        flag = deductionDepartmentRemaining(remainingId, estateExpenseBill.getId(), chargeType);
                    } else {
                        // 扣减余额
                        flag = deductionRemaining(rel.getRemainingId(), estateExpenseBill.getId(), chargeType);
                    }

                }catch (Exception e){
                    log.error("余额扣减账单异常  " + e.getMessage(), e);
                }

                List<UserDepartmentRef> byDepId = userDepartmentRefRepository.findByDepId(orgId);
                List<String> userId = byDepId.stream().map(UserDepartmentRef::getUserId).collect(Collectors.toList());
                List<User> byIdInAndType = userRepository.findByIdInAndType(userId, Short.parseShort("1"));
                User user = byIdInAndType.get(0);

                try {
                    if (remStatus != 3 && remStatus != 2) {
                        // 欠费冻结智能锁 生成违约金账单
                        if ((flag == DeductionEnum.NOT_PAY.getValue() || flag == DeductionEnum.PART_PAY.getValue())
                                && currentTime > estateExpenseBill.getShouldPayTime().getTime()) {
                            if (remStatus != 7) {
                                List<Integer> smartLockStatus = departmentBillList.stream().filter(s -> s.getDepId().equals(estateExpenseBill.getOrgId())
                                                && s.getSmartLockStatus().equals(estateExpenseBill.getChargeType()))
                                        .map(DepartmentBill::getSmartLockStatus).distinct().collect(Collectors.toList());
                                if (!CollectionUtils.isEmpty(smartLockStatus)) {
                                    billFreezeSmartLock(houseRemaining.getId(), smartLockStatus.get(0), user.getId());
                                } else {
                                    billFreezeSmartLock(houseRemaining.getId(), null, user.getId());
                                }
                            }


                        /*
                        生成违约金账单
                        */
                            String ruleId = estateExpenseBill.getRuleId();
                            if (StringUtils.isNotBlank(ruleId)) {
                                Optional<HouseExpenseBillRule> byId = houseExpenseBillRuleRepository.findById(ruleId);
                                if (byId.isPresent()) {
                                    HouseExpenseBillRule houseExpenseBillRule = byId.get();
                                    // 0不生成 1生成
                                    Integer violateStatus = houseExpenseBillRule.getViolateStatus();
                                    if (1 == violateStatus) {
                                        // 账单百分比
                                        BigDecimal ratio = BigDecimal.valueOf(parseDouble(houseExpenseBillRule.getViolateRatio()) / 10000);
                                        Integer cost = estateExpenseBill.getSurplusCost();
                                        BigDecimal surplusCost = new BigDecimal(cost);
                                        // 账单剩余未缴 * 违约金生成百分比
                                        BigDecimal growthCost = surplusCost.multiply(ratio).setScale(2, RoundingMode.HALF_UP);

                                        List<EstateViolateBill> violateList = estateViolateBillRepository.findByBillIdAndPaymentStatus(estateExpenseBill.getId(), 0);
                                        EstateViolateBill violateBill = new EstateViolateBill();
                                        // 未生成则生成
                                        if (CollectionUtils.isEmpty(violateList)) {
                                            violateBill.setBillId(estateExpenseBill.getId());
                                            violateBill.setBillType(chargeType);
                                            violateBill.setCost(0);
                                            violateBill.setMatchUserId(estateExpenseBill.getMatchUserId());
                                            violateBill.setGrowthCost(DataUtils.doubleToInteger(growthCost.doubleValue()));
                                            violateBill.setOrgId(orgId);
                                            violateBill.setRoomNumber(estateExpenseBill.getRoomNumber());
                                            violateBill.setRuleId(ruleId);
                                            violateBill.setHouseId(houseId);
                                            violateBill.setCreateTime(new Date());
                                            violateBill.setStatus(0);
                                            violateBill.setPaymentStatus(0);
                                            violateBill.setLeaseStatus(0);
                                        } else {
                                            BeanUtils.copyProperties(violateBill, violateList.get(0));
                                            violateBill.setGrowthCost(DataUtils.doubleToInteger(growthCost.doubleValue()));
                                        }
                                        EstateViolateBill save = estateViolateBillRepository.save(violateBill);
                                        // 待办事项
                                        propertyOtherItem(estateExpenseBill.getHouseId(), save.getId(), chargeType, redisService.getSystemUser(), estateExpenseBill.getMatchUserId());
                                    }
                                }
                            }
                        }
                    }
                }catch (Exception e){
                    log.error("余额扣减账单异常  " + e.getMessage(), e);
                }
            }

            // 租金押金
            for (EstateRentBill estateRentBill : rentBillList) {
                Integer flag = null;
                chargeType = estateRentBill.getChargeType() == 1 ? 8 : 9;
                orgId = estateRentBill.getOrgId();
                houseId = estateRentBill.getHouseId();

                Optional<House> byId1 = houseRepository.findById(houseId);
                House house = byId1.get();

                HouseRemainingRelation rel = houseRemainingRelationRepository.findByOrgIdAndHouseId(orgId, houseId);
                if (rel == null) {
                    log.warn("未找到账单对应余额账户  " + estateRentBill.getId());
                    continue;
                }
                Optional<HouseRemaining> remaining = houseRemainingRepository.findById(rel.getRemainingId());
                if (!remaining.isPresent()) {
                    log.warn("未找到账单对应余额账户  " + estateRentBill.getId());
                    continue;
                }
                HouseRemaining houseRemaining = remaining.get();
                // 状态：1正常 2已删除 3延期 4欠费
                Integer remStatus = houseRemaining.getStatus();

                // 单位承租人是否关联扣减账单
                Boolean depStatus = false;
                DepartmentRemainingRef depRef = new DepartmentRemainingRef();
                Long unitLesseeId = house.getUnitLesseeId();
                try {
                    if (unitLesseeId != null) {
                        depRef = departmentRemainingRefRepository.findByDepIdAndHouseIdAndOrgId(unitLesseeId, houseId, orgId);
                        // 其他费用代扣开启状态 : 0是 1否
                        if (depRef != null) {
                            if (depRef.getRentWithholdStatus() == 0) {
                                depStatus = true;
                            }
                        }
                    }
                    if (depStatus) {
                        Long remainingId = depRef.getRemainingId();
                        flag = deductionDepartmentRemaining(remainingId, estateRentBill.getId(), chargeType);
                    } else {
                        // 扣减余额
                        flag = deductionRemaining(rel.getRemainingId(), estateRentBill.getId(), chargeType);
                    }
                }catch (Exception e){
                    log.error("余额扣减账单" + e.getMessage(), e);
                }


                List<UserDepartmentRef> byDepId = userDepartmentRefRepository.findByDepId(orgId);
                List<String> userId = byDepId.stream().map(UserDepartmentRef::getUserId).collect(Collectors.toList());
                List<User> byIdInAndType = userRepository.findByIdInAndType(userId, Short.parseShort("1"));
                User user = byIdInAndType.get(0);

                try {
                    if (remStatus != 3 && remStatus != 2) {
                        // 欠费冻结智能锁
                        if ((flag == DeductionEnum.NOT_PAY.getValue() || flag == DeductionEnum.PART_PAY.getValue())
                                && currentTime > estateRentBill.getShouldPayTime().getTime()) {
                            if (remStatus != 7) {
                                List<Integer> smartLockStatus = departmentBillList.stream().filter(s -> s.getDepId().equals(estateRentBill.getOrgId()) &&
                                                s.getSmartLockStatus() == (estateRentBill.getChargeType() == 1 ? 8 : 9)).map(DepartmentBill::getSmartLockStatus)
                                        .distinct().collect(Collectors.toList());
                                if (!CollectionUtils.isEmpty(smartLockStatus)) {
                                    billFreezeSmartLock(rel.getRemainingId(), smartLockStatus.get(0), user.getId());
                                } else {
                                    billFreezeSmartLock(rel.getRemainingId(), null, user.getId());
                                }
                            }



                                /*
                                生成违约金账单
                                 */
                            String ruleId = estateRentBill.getRuleId();
                            if (StringUtils.isNotBlank(ruleId)) {
                                Optional<HouseExpenseBillRule> byId = houseExpenseBillRuleRepository.findById(ruleId);
                                if (byId.isPresent()) {
                                    HouseExpenseBillRule houseExpenseBillRule = byId.get();
                                    // 0不生成 1生成
                                    Integer violateStatus = houseExpenseBillRule.getViolateStatus();
                                    if (1 == violateStatus) {
                                        // 账单百分比
                                        BigDecimal ratio = BigDecimal.valueOf(parseDouble(houseExpenseBillRule.getViolateRatio()) / 10000);
                                        Integer cost = estateRentBill.getSurplusCost();
                                        BigDecimal surplusCost = new BigDecimal(cost);
                                        // 账单剩余未缴 * 违约金生成百分比
                                        BigDecimal growthCost = surplusCost.multiply(ratio).setScale(2, BigDecimal.ROUND_HALF_UP);

                                        List<EstateViolateBill> violateList = estateViolateBillRepository.findByBillIdAndPaymentStatus(estateRentBill.getId(), 0);
                                        EstateViolateBill violateBill = new EstateViolateBill();
                                        // 未生成则生成
                                        if (CollectionUtils.isEmpty(violateList)) {
                                            violateBill.setBillId(estateRentBill.getId());
                                            violateBill.setBillType(chargeType);
                                            violateBill.setCost(0);
                                            violateBill.setMatchUserId(estateRentBill.getMatchUserId());
                                            violateBill.setGrowthCost(DataUtils.doubleToInteger(growthCost.doubleValue()));
                                            violateBill.setOrgId(orgId);
                                            violateBill.setRoomNumber(estateRentBill.getRoomNumber());
                                            violateBill.setRuleId(ruleId);
                                            violateBill.setHouseId(houseId);
                                            violateBill.setCreateTime(new Date());
                                            violateBill.setStatus(0);
                                            violateBill.setPaymentStatus(0);
                                            violateBill.setLeaseStatus(0);
                                        } else {
                                            BeanUtils.copyProperties(violateBill, violateList.get(0));
                                            violateBill.setGrowthCost(DataUtils.doubleToInteger(growthCost.doubleValue()));
                                        }
                                        EstateViolateBill save = estateViolateBillRepository.save(violateBill);
                                        // 待办事项
                                        propertyOtherItem(estateRentBill.getHouseId(), save.getId(), chargeType, redisService.getSystemUser(), estateRentBill.getMatchUserId());
                                    }
                                }
                            }
                        }
                    }
                }catch (Exception e){
                    log.error("余额扣减账单" + e.getMessage(), e);
                }

            }
            log.info("余额扣减账单 remainingDeductionBill() 扣减账单 end");
        } catch (Exception e) {
            log.error("余额扣减账单" + e.getMessage(), e);
        }
    }

    /**
     * 其他费用缴费
     *
     * @param expenseBills
     * @param chargeType
     * @return
     */
    public List<EstateExpenseBill> deductionExpenseBill(List<EstateExpenseBill> expenseBills, Integer chargeType) {
        Long orgId = 0L;
        String houseId = "";
        List<EstateExpenseBill> payBillList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(expenseBills)) {
            for (EstateExpenseBill expenseBill : expenseBills) {
                orgId = expenseBill.getOrgId();
                houseId = expenseBill.getHouseId();

                Optional<House> byId = houseRepository.findById(houseId);
                House house = byId.get();

                // 单位承租人是否关联扣减账单
                Boolean depStatus = false;
                DepartmentRemainingRef depRef = new DepartmentRemainingRef();
                Long unitLesseeId = house.getUnitLesseeId();
                if (unitLesseeId != null) {
                    depRef = departmentRemainingRefRepository.findByDepIdAndHouseIdAndOrgId(unitLesseeId, houseId, orgId);
                    // 其他费用代扣开启状态 : 0是 1否
                    if (depRef != null) {
                        if (depRef.getElseWithholdStatus() == 0) {
                            depStatus = true;
                        }
                    }
                }
                if (depStatus) {
                    Long remainingId = depRef.getRemainingId();
                    Integer status = deductionDepartmentRemaining(remainingId, expenseBill.getId(), chargeType);
                    if (status == DeductionEnum.ALL_PAY.getValue()) {
                        payBillList.add(expenseBill);
                    }
                } else {
                    HouseRemainingRelation rel = houseRemainingRelationRepository.findByOrgIdAndHouseId(orgId, houseId);
                    // 完成缴费
                    if (rel != null) {
                        Integer flag = deductionRemaining(rel.getRemainingId(), expenseBill.getId(), chargeType);
                        if (flag == DeductionEnum.ALL_PAY.getValue()) {
                            payBillList.add(expenseBill);
                        }
                    }
                }
            }
        }
        return payBillList;
    }

    /**
     * 租金押金缴费
     *
     * @param estateRentBills
     * @param chargeType
     * @return
     */
    public List<EstateRentBill> deductionRentBill(List<EstateRentBill> estateRentBills, Integer chargeType) {
        Long orgId = 0L;
        String houseId = "";
        List<EstateRentBill> payBillList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(estateRentBills)) {
            for (EstateRentBill rentBill : estateRentBills) {
                orgId = rentBill.getOrgId();
                houseId = rentBill.getHouseId();
                Optional<House> byId = houseRepository.findById(houseId);
                House house = byId.get();

                // 单位承租人是否关联扣减账单
                Boolean depStatus = false;
                DepartmentRemainingRef depRef = new DepartmentRemainingRef();
                Long unitLesseeId = house.getUnitLesseeId();
                if (unitLesseeId != null) {
                    depRef = departmentRemainingRefRepository.findByDepIdAndHouseIdAndOrgId(unitLesseeId, houseId, orgId);
                    // 租金押金代扣开启状态 : 0是 1否
                    if (depRef != null) {
                        if (depRef.getRentWithholdStatus() == 0) {
                            depStatus = true;
                        }
                    }
                }
                if (depStatus) {
                    Long remainingId = depRef.getRemainingId();
                    Integer status = deductionDepartmentRemaining(remainingId, rentBill.getId(), chargeType);
                    if (status == DeductionEnum.ALL_PAY.getValue()) {
                        payBillList.add(rentBill);
                    }
                } else {
                    HouseRemainingRelation rel = houseRemainingRelationRepository.findByOrgIdAndHouseId(orgId, houseId);
                    // 完成缴费
                    if (rel != null) {
                        Integer flag = deductionRemaining(rel.getRemainingId(), rentBill.getId(), chargeType);
                        if (flag == DeductionEnum.ALL_PAY.getValue()) {
                            payBillList.add(rentBill);
                        }
                    }
                }

            }
        }
        return payBillList;
    }

    /**
     * 扣减余额
     *
     * @param remainingId 余额id
     * @param billId      账单id
     * @param chargeType  扣款类型 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8租金 9押金
     */
    public Integer deductionRemaining(Long remainingId, Long billId, Integer chargeType) {
        Integer flag = DeductionEnum.NOT_PAY.getValue();
        Optional<HouseRemaining> rem = houseRemainingRepository.findById(remainingId);
        if (!rem.isPresent()) {
            log.info("未查到余额账户 {}", remainingId);
            return flag;
        }
        HouseRemaining houseRemaining = rem.get();
        Integer balanceFee = houseRemaining.getBalanceFee();
        // 操作金额
        Integer operateMoney = 0;
        BigDecimal remaining = new BigDecimal(balanceFee);
        final Date updateTime = new Date();
        // 系统id
        String systemUser = redisService.getSystemUser();
        if (balanceFee <= 0) {
            log.info("余额不足 {}", remainingId);
            return flag;
        }
        if (chargeType != 8 && chargeType != 9) {// 其他费用
            Optional<EstateExpenseBill> expenseBill = estateExpenseBillRepository.findById(billId);
            EstateExpenseBill estateExpenseBill = expenseBill.get();
            Integer cost = estateExpenseBill.getSurplusCost();
            BigDecimal billCost = new BigDecimal(cost);
            if (balanceFee - cost <= 0) {// 部分缴费
                operateMoney = balanceFee;

                int paymentStatus = DeductionEnum.PART_PAY.getValue();
                if (balanceFee - cost == 0) {
                    paymentStatus = DeductionEnum.ALL_PAY.getValue();
                }
                // 账单费用抵扣
                cost = Integer.parseInt(billCost.subtract(remaining).toString());
                estateExpenseBill.setSurplusCost(cost);
                estateExpenseBill.setPaymentStatus(paymentStatus);
                estateExpenseBill.setPaymentTime(updateTime);
                estateExpenseBill.setOperatorId(systemUser);
                estateExpenseBill.setPaymentChannel(PaymentTypeEnum.Remaining.getValue());
                EstateExpenseBill saveBill = estateExpenseBillRepository.save(estateExpenseBill);

                // 余额扣减
                houseRemaining.setBalanceFee(0);
                houseRemaining.setLastUpdateTime(updateTime);
                HouseRemaining saveRemaining = houseRemainingRepository.save(houseRemaining);

                // 余额操作记录
                HouseRemainingRecord record = new HouseRemainingRecord();
                record.setBillId(saveBill.getId());
                record.setRemainingId(saveRemaining.getId());
                record.setOperateMoney(operateMoney);
                record.setOperatorId(systemUser);
                record.setOperateName(SystemEnum.SYSTEM_USER_NAME.getValue());
                record.setLastUpdateTime(updateTime);
                record.setUpdateStatus(PaymentTypeEnum.SUCCESS.getValue());
                record.setCause(PaymentCauseEnum.SYSTEM_DEDUCTION.getValue());
                record.setOperateStatus(PaymentTypeEnum.BUCKLE.getValue());
                record.setBillStatus(PaymentTypeEnum.EXPENSE_BILL.getValue());
                // 状态：1正常 2已删除
                record.setStatus(1);
                houseRemainingRecordRepository.save(record);

                // 余额变动待办事项
                houseRemainingItem(saveBill.getHouseId(), saveBill.getMatchUserId(), saveRemaining.getId(), chargeType, operateMoney, systemUser, saveBill.getOrgId());
                flag = paymentStatus;
            } else {
                operateMoney = cost;
                // 账单费用扣减
                cost = Integer.parseInt(remaining.subtract(billCost).toString());
                estateExpenseBill.setSurplusCost(0);
                estateExpenseBill.setPaymentTime(updateTime);
                estateExpenseBill.setOperatorId(systemUser);
                estateExpenseBill.setPaymentChannel(PaymentTypeEnum.Remaining.getValue());
                estateExpenseBill.setPaymentStatus(RrentBillPaymentStatusTypeEnum.PAY.getValue());
                EstateExpenseBill saveBill = estateExpenseBillRepository.save(estateExpenseBill);

                // 余额扣减
                houseRemaining.setBalanceFee(cost);
                houseRemaining.setLastUpdateTime(updateTime);
                HouseRemaining saveRemaining = houseRemainingRepository.save(houseRemaining);

                // 余额操作记录
                HouseRemainingRecord record = new HouseRemainingRecord();
                record.setBillId(saveBill.getId());
                record.setRemainingId(saveRemaining.getId());
                record.setOperateMoney(operateMoney);
                record.setOperatorId(systemUser);
                record.setOperateName(SystemEnum.SYSTEM_USER_NAME.getValue());
                record.setLastUpdateTime(updateTime);
                record.setUpdateStatus(PaymentTypeEnum.SUCCESS.getValue());
                record.setCause(PaymentCauseEnum.SYSTEM_DEDUCTION.getValue());
                record.setOperateStatus(PaymentTypeEnum.BUCKLE.getValue());
                record.setBillStatus(PaymentTypeEnum.EXPENSE_BILL.getValue());
                // 状态：1正常 2已删除
                record.setStatus(1);
                houseRemainingRecordRepository.save(record);


                // 余额变动待办事项
                houseRemainingItem(saveBill.getHouseId(), saveBill.getMatchUserId(), saveRemaining.getId(), chargeType, operateMoney, systemUser, saveBill.getOrgId());
                // 其他费用待办事项
                propertyOtherItem(saveBill.getId());

                flag = DeductionEnum.ALL_PAY.getValue();
            }
        } else {// 租金押金
            Optional<EstateRentBill> rentBill = estateRentBillRepository.findById(billId);
            EstateRentBill estateRentBill = rentBill.get();
            Integer cost = estateRentBill.getSurplusCost();
            BigDecimal billCost = new BigDecimal(cost);

            // 1租金 2押金
            Integer rentBillChargeType = estateRentBill.getChargeType();
            if (rentBillChargeType == 1) {// 租金
                if (balanceFee - cost <= 0) {
                    operateMoney = balanceFee;

                    int paymentStatus = DeductionEnum.PART_PAY.getValue();
                    if (balanceFee - cost == 0) {
                        paymentStatus = DeductionEnum.ALL_PAY.getValue();
                    }
                    // 账单费用抵扣
                    cost = Integer.parseInt(billCost.subtract(remaining).toString());
                    estateRentBill.setSurplusCost(cost);
                    estateRentBill.setPaymentStatus(paymentStatus);
                    estateRentBill.setPaymentTime(updateTime);
                    EstateRentBill saveBill = estateRentBillRepository.save(estateRentBill);

                    // 余额扣减
                    houseRemaining.setBalanceFee(0);
                    houseRemaining.setLastUpdateTime(updateTime);
                    HouseRemaining saveRemaining = houseRemainingRepository.save(houseRemaining);

                    // 余额操作记录
                    HouseRemainingRecord record = new HouseRemainingRecord();
                    record.setBillId(saveBill.getId());
                    record.setRemainingId(saveRemaining.getId());
                    record.setOperateMoney(operateMoney);
                    record.setOperatorId(systemUser);
                    record.setOperateName(SystemEnum.SYSTEM_USER_NAME.getValue());
                    record.setLastUpdateTime(updateTime);
                    record.setUpdateStatus(PaymentTypeEnum.SUCCESS.getValue());
                    record.setCause(PaymentCauseEnum.SYSTEM_DEDUCTION.getValue());
                    record.setOperateStatus(PaymentTypeEnum.BUCKLE.getValue());
                    record.setBillStatus(PaymentTypeEnum.RENT_BILL.getValue());
                    // 状态：1正常 2已删除
                    record.setStatus(1);
                    houseRemainingRecordRepository.save(record);

                    // 余额变动待办事项
                    houseRemainingItem(saveBill.getHouseId(), saveBill.getMatchUserId(), saveRemaining.getId(), chargeType, operateMoney, systemUser, saveBill.getOrgId());
                    flag = paymentStatus;
                } else {
                    operateMoney = cost;
                    // 账单费用扣减
                    cost = Integer.parseInt(remaining.subtract(billCost).toString());
                    estateRentBill.setSurplusCost(0);
                    estateRentBill.setPaymentTime(updateTime);
                    estateRentBill.setPaymentStatus(RrentBillPaymentStatusTypeEnum.PAY.getValue());
                    EstateRentBill saveBill = estateRentBillRepository.save(estateRentBill);

                    // 余额扣减
                    houseRemaining.setBalanceFee(cost);
                    houseRemaining.setLastUpdateTime(updateTime);
                    HouseRemaining saveRemaining = houseRemainingRepository.save(houseRemaining);

                    // 余额操作记录
                    HouseRemainingRecord record = new HouseRemainingRecord();
                    record.setBillId(saveBill.getId());
                    record.setRemainingId(saveRemaining.getId());
                    record.setOperateMoney(operateMoney);
                    record.setOperatorId(systemUser);
                    record.setOperateName(SystemEnum.SYSTEM_USER_NAME.getValue());
                    record.setLastUpdateTime(updateTime);
                    record.setUpdateStatus(PaymentTypeEnum.SUCCESS.getValue());
                    record.setCause(PaymentCauseEnum.SYSTEM_DEDUCTION.getValue());
                    record.setOperateStatus(PaymentTypeEnum.BUCKLE.getValue());
                    record.setBillStatus(PaymentTypeEnum.RENT_BILL.getValue());
                    // 状态：1正常 2已删除
                    record.setStatus(1);
                    houseRemainingRecordRepository.save(record);

                    // 余额变动待办事项
                    houseRemainingItem(saveBill.getHouseId(), saveBill.getMatchUserId(), saveRemaining.getId(), chargeType, operateMoney, systemUser, saveBill.getOrgId());
                    // 租金/押金待办事项
                    propertyRentItem(saveBill.getId());
                    flag = DeductionEnum.ALL_PAY.getValue();
                }
            } else {
                // 押金
                if (balanceFee - cost <= 0) {
                    operateMoney = balanceFee;

                    int paymentStatus = DeductionEnum.PART_PAY.getValue();
                    if (balanceFee - cost == 0) {
                        paymentStatus = DeductionEnum.ALL_PAY.getValue();
                    }
                    // 账单费用抵扣
                    cost = Integer.parseInt(billCost.subtract(remaining).toString());
                    estateRentBill.setSurplusCost(cost);
                    estateRentBill.setPaymentStatus(paymentStatus);
                    estateRentBill.setPaymentTime(updateTime);
                    EstateRentBill saveBill = estateRentBillRepository.save(estateRentBill);

                    // 余额扣减
                    houseRemaining.setBalanceFee(0);
                    houseRemaining.setCashPledge(operateMoney);
                    houseRemaining.setLastUpdateTime(updateTime);
                    HouseRemaining saveRemaining = houseRemainingRepository.save(houseRemaining);

                    // 余额操作记录
                    HouseRemainingRecord record = new HouseRemainingRecord();
                    record.setBillId(saveBill.getId());
                    record.setRemainingId(saveRemaining.getId());
                    record.setOperateMoney(operateMoney);
                    record.setOperatorId(systemUser);
                    record.setOperateName(SystemEnum.SYSTEM_USER_NAME.getValue());
                    record.setLastUpdateTime(updateTime);
                    record.setUpdateStatus(PaymentTypeEnum.SUCCESS.getValue());
                    record.setCause(PaymentCauseEnum.SYSTEM_DEDUCTION.getValue());
                    record.setOperateStatus(PaymentTypeEnum.BUCKLE.getValue());
                    record.setBillStatus(PaymentTypeEnum.DEPOSIT_BILL.getValue());
                    // 状态：1正常 2已删除
                    record.setStatus(1);
                    houseRemainingRecordRepository.save(record);

                    // 余额变动待办事项
                    houseRemainingItem(saveBill.getHouseId(), saveBill.getMatchUserId(), saveRemaining.getId(), chargeType, operateMoney, systemUser, saveBill.getOrgId());
                    flag = paymentStatus;
                } else {
                    operateMoney = cost;
                    // 账单费用扣减
                    cost = Integer.parseInt(remaining.subtract(billCost).toString());
                    estateRentBill.setSurplusCost(0);
                    estateRentBill.setPaymentTime(updateTime);
                    estateRentBill.setPaymentStatus(RrentBillPaymentStatusTypeEnum.PAY.getValue());
                    EstateRentBill saveBill = estateRentBillRepository.save(estateRentBill);

                    // 余额扣减
                    houseRemaining.setBalanceFee(cost);
                    houseRemaining.setCashPledge(operateMoney);
                    houseRemaining.setLastUpdateTime(updateTime);
                    HouseRemaining saveRemaining = houseRemainingRepository.save(houseRemaining);

                    // 余额操作记录
                    HouseRemainingRecord record = new HouseRemainingRecord();
                    record.setBillId(saveBill.getId());
                    record.setRemainingId(saveRemaining.getId());
                    record.setOperateMoney(operateMoney);
                    record.setOperatorId(systemUser);
                    record.setOperateName(SystemEnum.SYSTEM_USER_NAME.getValue());
                    record.setLastUpdateTime(updateTime);
                    record.setUpdateStatus(PaymentTypeEnum.SUCCESS.getValue());
                    record.setCause(PaymentCauseEnum.SYSTEM_DEDUCTION.getValue());
                    record.setOperateStatus(PaymentTypeEnum.BUCKLE.getValue());
                    record.setBillStatus(PaymentTypeEnum.DEPOSIT_BILL.getValue());
                    // 状态：1正常 2已删除
                    record.setStatus(1);
                    houseRemainingRecordRepository.save(record);

                    // 余额变动待办事项
                    houseRemainingItem(saveBill.getHouseId(), saveBill.getMatchUserId(), saveRemaining.getId(), chargeType, operateMoney, systemUser, saveBill.getOrgId());
                    // 租金/押金待办事项
                    propertyRentItem(saveBill.getId());
                    flag = DeductionEnum.ALL_PAY.getValue();
                }
            }

        }
        return flag;
    }


    /**
     * 扣减单位账户余额
     *
     * @param remainingId 余额id
     * @param billId      账单id
     * @param chargeType  扣款类型 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8租金 9押金
     */
    @Transactional
    public Integer deductionDepartmentRemaining(Long remainingId, Long billId, Integer chargeType) {
        String chargeName = null;
        switch (chargeType) {  //  1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8租金 9押金
            case 1:
                chargeName = "水费";
                break;
            case 2:
                chargeName = "电费";
                break;
            case 3:
                chargeName = "物业费";
                break;
            case 4:
                chargeName = "宽带费";
                break;
            case 5:
                chargeName = "电视费";
                break;
            case 6:
                chargeName = "燃气费";
                break;
            case 7:
                chargeName = "暖气费";
                break;
            case 8:
                chargeName = "租金";
                break;
            case 9:
                chargeName = "押金";
                break;
        }
        Integer flag = DeductionEnum.NOT_PAY.getValue();
        Optional<DepartmentRemaining> depRemaining = departmentRemainingRepository.findById(remainingId);
        if (!depRemaining.isPresent()) {
            log.info("未查到余额账户 {}", remainingId);
            return flag;
        }
        DepartmentRemaining departmentRemaining = depRemaining.get();

        Integer balanceFee = departmentRemaining.getBalanceFee();
        // 操作金额
        Integer operateMoney = 0;
        BigDecimal remaining = new BigDecimal(balanceFee);
        final Date updateTime = new Date();
        // 系统id
        String systemUser = redisService.getSystemUser();
        if (balanceFee <= 0) {
            log.info("余额不足 {}", remainingId);
            return flag;
        }
        if (chargeType != 8 && chargeType != 9) {// 其他费用
            Optional<EstateExpenseBill> expenseBill = estateExpenseBillRepository.findById(billId);
            EstateExpenseBill estateExpenseBill = expenseBill.get();
            Integer cost = estateExpenseBill.getSurplusCost();
            if (balanceFee < cost) {
                log.info("余额不足 {}", remainingId);
                return flag;
            }
            BigDecimal billCost = new BigDecimal(cost);
            // 账单费用扣减
            cost = remaining.subtract(billCost).intValue();
            estateExpenseBill.setSurplusCost(0);
            estateExpenseBill.setPaymentStatus(DeductionEnum.ALL_PAY.getValue());
            estateExpenseBill.setPaymentTime(updateTime);
            estateExpenseBill.setOperatorId(systemUser);
            estateExpenseBill.setPaymentChannel(PaymentTypeEnum.Remaining.getValue());
            EstateExpenseBill saveBill = estateExpenseBillRepository.save(estateExpenseBill);

            // 余额扣减
            departmentRemaining.setBalanceFee(cost);
            departmentRemaining.setLastUpdateTime(updateTime);
            DepartmentRemaining saveRemaining = departmentRemainingRepository.save(departmentRemaining);

            // 余额操作记录
            DepartmentRemainingRecord record = new DepartmentRemainingRecord();
            record.setHouseId(estateExpenseBill.getHouseId());
            record.setBillId(saveBill.getId());
            record.setRemainingId(saveRemaining.getId());
            record.setOperateMoney(billCost.intValue());
            record.setOperatorId(systemUser);
            record.setUpdateTime(updateTime);
            record.setUpdateStatus(PaymentTypeEnum.SUCCESS.getValue());
            record.setCause(PaymentCauseEnum.SYSTEM_DEDUCTION.getValue() + estateExpenseBill.getStartTime().toString() + "-" + estateExpenseBill.getEndTime().toString() + "，" + chargeName);
            record.setOperateStatus(PaymentTypeEnum.BUCKLE.getValue());
            record.setBillStatus(chargeType);
            // 状态：1正常 2已删除
            record.setStatus(1);
            departmentRemainingRecordRepository.save(record);

            // 其他费用待办事项
            propertyOtherItem(saveBill.getId());
            flag = DeductionEnum.ALL_PAY.getValue();

        } else {
            Optional<EstateRentBill> rentBill = estateRentBillRepository.findById(billId);
            EstateRentBill estateRentBill = rentBill.get();
            Integer cost = estateRentBill.getSurplusCost();
            BigDecimal billCost = new BigDecimal(cost);

            // 1租金 2押金
            Integer rentBillChargeType = estateRentBill.getChargeType();
            if (balanceFee < cost) {
                log.info("余额不足 {}", remainingId);
                return flag;
            }

            if (rentBillChargeType == 1) {// 租金

                // 账单费用抵扣
                cost = remaining.subtract(billCost).intValue();

                estateRentBill.setSurplusCost(0);
                estateRentBill.setPaymentStatus(DeductionEnum.ALL_PAY.getValue());
                estateRentBill.setPaymentTime(updateTime);
                EstateRentBill saveBill = estateRentBillRepository.save(estateRentBill);

                // 余额扣减
                departmentRemaining.setBalanceFee(cost);
                departmentRemaining.setLastUpdateTime(updateTime);
                DepartmentRemaining saveRemaining = departmentRemainingRepository.save(departmentRemaining);

                // 余额操作记录
                DepartmentRemainingRecord record = new DepartmentRemainingRecord();
                record.setHouseId(saveBill.getHouseId());
                record.setBillId(saveBill.getId());
                record.setRemainingId(saveRemaining.getId());
                record.setOperateMoney(billCost.intValue());
                record.setOperatorId(systemUser);
                record.setUpdateTime(updateTime);
                record.setUpdateStatus(1);
                record.setCause(PaymentCauseEnum.SYSTEM_DEDUCTION.getValue() + saveBill.getStartTime().toString() + "-" + saveBill.getEndTime().toString() + "，" + chargeName);
                record.setOperateStatus(PaymentTypeEnum.BUCKLE.getValue());
                record.setBillStatus(chargeType);
                record.setStatus(1);
                departmentRemainingRecordRepository.save(record);

                // 租金/押金待办事项
                propertyRentItem(saveBill.getId());
                flag = DeductionEnum.ALL_PAY.getValue();


            } else {
                // 押金
                operateMoney = cost;
                // 账单费用扣减
                cost = remaining.subtract(billCost).intValue();

                estateRentBill.setSurplusCost(0);
                estateRentBill.setPaymentStatus(DeductionEnum.ALL_PAY.getValue());
                estateRentBill.setPaymentTime(updateTime);
                estateRentBill.setPaymentStatus(RrentBillPaymentStatusTypeEnum.PAY.getValue());
                EstateRentBill saveBill = estateRentBillRepository.save(estateRentBill);

                // 余额扣减
                departmentRemaining.setBalanceFee(cost);
                departmentRemaining.setCashPledge(departmentRemaining.getCashPledge() + billCost.intValue());
                departmentRemaining.setLastUpdateTime(updateTime);
                DepartmentRemaining saveRemaining = departmentRemainingRepository.save(departmentRemaining);

                // 余额操作记录
                DepartmentRemainingRecord record = new DepartmentRemainingRecord();
                record.setHouseId(saveBill.getHouseId());
                record.setBillId(saveBill.getId());
                record.setRemainingId(saveRemaining.getId());
                record.setOperateMoney(billCost.intValue());
                record.setOperatorId(systemUser);
                record.setUpdateTime(updateTime);
                record.setUpdateStatus(1);
                record.setCause(PaymentCauseEnum.SYSTEM_DEDUCTION.getValue() + saveBill.getStartTime().toString() + "-" + saveBill.getEndTime().toString() + "，" + chargeName);
                record.setOperateStatus(PaymentTypeEnum.BUCKLE.getValue());
                record.setBillStatus(chargeType);
                record.setStatus(1);
                departmentRemainingRecordRepository.save(record);

                // 租金/押金待办事项
                propertyRentItem(saveBill.getId());
                flag = DeductionEnum.ALL_PAY.getValue();

            }

        }
        return flag;
    }

    public List<Map<String, String>> dateList(Date tempDate, Date endDate, int month) {

        List<Map<String, String>> dateList = new ArrayList<>();
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        Calendar startCal = Calendar.getInstance();
        Calendar endCal = Calendar.getInstance();

        for (; ; ) {
            Map<String, String> map = new HashMap<>();
            startCal.setTime(tempDate);
            String start = df.format(startCal.getTime());
            map.put("start", start);
            startCal.add(Calendar.MONTH, month);// 下一个开始日期

            endCal.setTime(startCal.getTime());
            endCal.add(Calendar.DAY_OF_MONTH, -1);
            Date temEnd = endCal.getTime();
            // 拆分后的结束时间 > 周期结束时间
            if (temEnd.getTime() >= endDate.getTime()) {
                map.put("end", df.format(endDate));
                dateList.add(map);
                break;
            } else {
                tempDate = startCal.getTime();
                map.put("end", df.format(temEnd));
                dateList.add(map);
            }
        }

        return dateList;
    }

    /**
     * 余额扣款待办事项
     *
     * @param houseId     房屋ID
     * @param matchUserId 承租人ID
     * @param remainingId 余额ID
     * @param chargeType  扣款类型 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8租金 9押金
     * @param cost        金额
     * @param operatorId  操作人ID
     * @param orgId       收款机构ID
     */
    public void houseRemainingItem(String houseId, String matchUserId, Long remainingId, Integer chargeType, Integer cost, String operatorId, Long orgId) {
        String yuan = fenToYuan(String.valueOf(cost));
        String chargeName = null;
        switch (chargeType) {  //  1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8租金 9押金
            case 1:
                chargeName = "水费";
                break;
            case 2:
                chargeName = "电费";
                break;
            case 3:
                chargeName = "物业费";
                break;
            case 4:
                chargeName = "宽带费";
                break;
            case 5:
                chargeName = "电视费";
                break;
            case 6:
                chargeName = "燃气费";
                break;
            case 7:
                chargeName = "暖气费";
                break;
            case 8:
                chargeName = "租金";
                break;
            case 9:
                chargeName = "押金";
                break;
        }

//        String sql="select * from (\n" +
//                "select a.mobile as mobile ,a.community_house_id as houseId  , a.user_id as userId  from  saas_community_house_user a\n" +
//                "where   a.status = 1 \n" +
//                "UNION\n" +
//                "select b.phone as mobile , a.house_id as houseId , a.match_user_id as userId from   saas_house_match_user a \n" +
//                "LEFT JOIN saas_app_user b on b.id= a.match_user_id\n" +
//                "where 1=1\n" +
//                "UNION \n" +
//                "select b.mobile as mobile , a.house_id as houseId , c.id as userId from   saas_house_match_user a \n" +
//                "LEFT JOIN saas_house_eligible_apply_cohabit b on b.apply_id= a.apply_id\n" +
//                "LEFT JOIN saas_app_user c on c.phone = b.mobile \n" +
//                "where 1=1 and b.mobile is not null \n" +
//                ") t1 where t1.houseId ='"+houseId+"' ";

        /**
         * qixi
         * 2022-12-28 11:32
         * 余额变动承租人和已授权账单的同住人可见
         *
         */
        String sql = "select * from (select a.mobile as mobile ,a.community_house_id as houseId  , a.user_id as userId  " +
                "from  saas_community_house_user a\n" +
                "where a.status = 1 and a.type = 1  \n" +
                "UNION\n" +
                "select b.phone as mobile , a.house_id as houseId , a.match_user_id as userId from   saas_house_match_user a\n" +
                "LEFT JOIN saas_app_user b on b.id= a.match_user_id\n" +
                "where 1=1\n" +
                ") t1 where t1.houseId ='" + houseId + "' ";


        String where = " and 1=1 ";

        List<CommunityHouseUser> CommunityHouseUserList = jdbcTemplate.query(sql + where, new BeanPropertyRowMapper<>(CommunityHouseUser.class));

        CommunityHouseUserList = CommunityHouseUserList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(CommunityHouseUser::getMobile))), ArrayList::new));
        for (CommunityHouseUser communityHouseUser : CommunityHouseUserList) {
            // 账单扣款余额变动
            BacklogItem backlogItem = new BacklogItem();
            backlogItem.setHouseId(houseId);
            backlogItem.setOrgId(orgId);
            backlogItem.setType(BacklogItemTypeEnum.REMAINING_CHANGE.getValue());
            backlogItem.setTitle("余额变动");
            backlogItem.setContent(chargeName + "账单，系统扣款：" + yuan + "元");
            backlogItem.setBusinessStatus("待查看");
            backlogItem.setHandleStatus(0);
            backlogItem.setOperatorId(operatorId);// 操作人id
            backlogItem.setMatchUserId(matchUserId);
            backlogItem.setPhone(communityHouseUser.getMobile());
            backlogItem.setCreateTime(new Date());
            BacklogItem save = backlogItemRepository.save(backlogItem);

            BacklogItemHouseRemaining houseRemaining = new BacklogItemHouseRemaining();
            houseRemaining.setBacklogItemId(save.getId());
            houseRemaining.setRemainingId(remainingId);
            backlogItemHouseRemainingRepository.save(houseRemaining);


            Optional<AppUser> byId = appUserRepository.findById(matchUserId);
            if (byId.isPresent()){
                Optional<HouseRemaining> byRemainingId = houseRemainingRepository.findById(remainingId);
                HouseRemaining houseRemaining1 = byRemainingId.get();
                AppUser appUser = byId.get();

                SubscribeVo subscribeVo = new SubscribeVo();
                subscribeVo.setCost(Double.valueOf(yuan));
                subscribeVo.setOpenId(appUser.getOpenId());
                subscribeVo.setBillTypeName("支付"+chargeName);
                subscribeVo.setBalanceFee(fenToYuan(houseRemaining1.getBalanceFee().toString()));

                subscribeService.sendDeductionBalanceMsg(subscribeVo);
            }

        }
    }

    /**
     * 账单欠费冻结智能锁
     *
     * @param remainingId     余额id
     * @param smartLockStatus 冻结类型:1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8押金  9租金 10退租
     * @return
     */
    public Boolean billFreezeSmartLock(Long remainingId, Integer smartLockStatus, String userId) {
        String chargeName;
        Boolean flag = false;
        final Date date = new Date();
        Optional<HouseRemaining> houseRemaining = houseRemainingRepository.findById(remainingId);
        if (!houseRemaining.isPresent()) {
            log.error("余额账户未找到" + remainingId);
            return flag;
        }
        HouseRemaining remaining = houseRemaining.get();

        Integer rmStatus = remaining.getStatus();
        if (3 == rmStatus) {
            Date deferredEndTime = remaining.getDeferredEndTime();
            if (date.getTime() < deferredEndTime.getTime() && remaining.getBalanceFee() > 0) {
                return flag;
            }
        }
        // 1正常 2已删除 3延期 4欠费 5已退租 6已退款 7已冻结
        remaining.setStatus(7);
        if (null == smartLockStatus) {
            return flag;
        }

        String houseId = remaining.getHouseId();
        // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8押金  9租金 10退租
        switch (smartLockStatus) {
            case 1:
                chargeName = "水费";
                flag = freezeSmartLock(houseId, chargeName, userId);
                break;
            case 2:
                chargeName = "电费";
                flag = freezeSmartLock(houseId, chargeName, userId);
                break;
            case 3:
                chargeName = "物业费";
                flag = freezeSmartLock(houseId, chargeName, userId);
                break;
            case 4:
                chargeName = "宽带费";
                flag = freezeSmartLock(houseId, chargeName, userId);
                break;
            case 5:
                chargeName = "电视费";
                flag = freezeSmartLock(houseId, chargeName, userId);
                break;
            case 6:
                chargeName = "燃气费";
                flag = freezeSmartLock(houseId, chargeName, userId);
                break;
            case 7:
                chargeName = "暖气费";
                flag = freezeSmartLock(houseId, chargeName, userId);
                break;
            case 8:
                chargeName = "租金";
                flag = freezeSmartLock(houseId, chargeName, userId);
                break;
            case 9:
                chargeName = "押金";
                flag = freezeSmartLock(houseId, chargeName, userId);
                break;
        }
        houseRemainingRepository.save(remaining);
        return flag;
    }

    /**
     * 根据房屋id 冻结整屋智能锁授权
     *
     * @param houseId
     * @param chargeName
     * @return
     */
    private Boolean freezeSmartLock(String houseId, String chargeName, String userId) {
        chargeName = chargeName + "欠费，系统自动冻结";
        Boolean flag = false;
        String id = houseId;

        // 判断是否合租
        List<SmartLockAuth> smartLockAuths = new ArrayList<>();
        Optional<House> byId = houseRepository.findById(houseId);
        if (byId.isPresent()) {
            House house = byId.get();
            if (house.getHousemateId() != null) {
                smartLockAuths = smartLockAuthRepository.findBySubHouseId(houseId);
            } else {
                smartLockAuths = smartLockAuthRepository.findByHouseId(id);
            }
        }


        Date date = new Date();
        String systemUser = redisService.getSystemUser();
        if (!CollectionUtils.isEmpty(smartLockAuths)) {
            for (SmartLockAuth smartLockAuth : smartLockAuths) {
                Long lockAuthId = smartLockAuth.getId();
                // 单用户授权冻结, 一次冻结密码、身份证、CPU、指纹
                Optional<SmartLock> lockOptional = smartLockRepository.findById(smartLockAuth.getLockId());
                if (!lockOptional.isPresent()) {
                    break;
                }
                SmartLock smartLock = lockOptional.get();
                SmartLockPwd pwd = smartLockPwdRepository.findByLockAuthId(lockAuthId);
                List<SmartLockCard> cards = smartLockCardRepository.findByLockAuthId(lockAuthId);
                List<SmartLockFingerprint> fingerprint = smartLockFingerprintRepository.findByLockAuthId(lockAuthId);
                SmartLockBle ble = smartLockBleRepository.findByLockAuthId(lockAuthId);
                SmartLockFace face = smartLockFaceRepository.findByLockAuthId(lockAuthId);
                if (pwd != null || !cards.isEmpty() || !fingerprint.isEmpty() || ble != null|| face != null) {
                    // 新增冻结记录
                    String smartLockHouseId = smartLock.getHouseId();
                    // String matchUserName = smartLock.getMatchUserName();
                    String communityName = smartLock.getCommunityName();
                    String buildName = smartLock.getBuildName();
                    String unitName = smartLock.getUnitName();
                    String roomNumber = smartLock.getRoomNumber();

                    LockFrozen lockFrozen = new LockFrozen();
                    lockFrozen.setType(1);
                    lockFrozen.setLockId(smartLockAuth.getLockId());
                    lockFrozen.setLockAuditId(lockAuthId);
                    lockFrozen.setHouseId(smartLockHouseId);
                    lockFrozen.setMatchUserName(smartLockAuth.getUserName());
                    lockFrozen.setCommunityName(communityName);
                    lockFrozen.setBuildName(buildName);
                    lockFrozen.setUnitName(unitName);
                    lockFrozen.setRoomNumber(roomNumber);
                    lockFrozen.setOperationId(userId);
                    lockFrozen.setOperationTime(date);
                    lockFrozen.setOperationState(2);
                    if (StringUtils.isNotBlank(chargeName)) {
                        lockFrozen.setReason(chargeName);
                    }
                    LockFrozen frozenSave = lockFrozenRepository.save(lockFrozen);

                    // 冻结密码
                    if (pwd != null) {
                        SmartLockVO smartLockVO = new SmartLockVO();
                        smartLockVO.setSn(smartLock.getSn());
                        smartLockVO.setIndex(pwd.getPwdIndex());
                        smartLockVO.setAuthInfoId(lockAuthId);
                        Integer authType = pwd.getAuthType();
                        if (authType == 1 || authType == 2) {
                            smartLockVO.setAuthType(LockAuthTypeEnum.NORMAL_PASS.getValue());
                        } else if (authType == 3) {
                            smartLockVO.setAuthType(LockAuthTypeEnum.TIMES_PASS.getValue());
                            smartLockVO.setTimes(pwd.getTimes());
                        }
                        smartLockVO.setSuspend(1);// 0:解冻 1:冻结
                        smartLockVO.setLockFrozenId(frozenSave.getId());
                        smartLockVO.setIndexNum(pwd.getPwdIndexNum());
                        smartLockVO.setPwdType(pwd.getType());
                        smartLockVO.setIdentification(pwd.getIdentification());
                        // 亚略特
                        if (smartLock.getBrandId() == 3L) {
                            smartLockVO.setfAuthorizationID(pwd.getfAuthorizationId());
                        }

                        ResultBean<String> stringResultBean = smartLockBrandService.freezeOrUnfreeze(smartLockVO,
                                smartLock.getBrandId(), XzLockOperatorTypeEnum.PWD.getValue());
                        String msg = stringResultBean.getMsg();
                        String code = stringResultBean.getCode();
                        if (!code.equals(StatusCode.SUCCESS_CODE_10000.getErrorCode())) {
                            log.error("LockAppService frozenOrUnfrozenAuth---> " + msg);
                            // 失败，删除冻结记录
                            lockFrozenRepository.deleteById(frozenSave.getId());
                        } else {
                            // 冻结后默认待执行
                            pwd.setStatus(0);
                            smartLockPwdRepository.save(pwd);
                            // 亚略特
                            // if (smartLock.getBrandId() == 3L) {
                            yltUpdateStatus(pwd, null, null, null, null, 1, stringResultBean, smartLockAuth, lockFrozen, smartLock);
                            //}
                        }
                    }

                    // 冻结卡
                    if (!cards.isEmpty()) {
                        for (SmartLockCard card : cards) {
                            SmartLockVO smartLockVO = new SmartLockVO();
                            smartLockVO.setSn(smartLock.getSn());
                            smartLockVO.setIndex(card.getCardIndex());
                            smartLockVO.setAuthInfoId(lockAuthId);
                            smartLockVO.setCardType(card.getType());
                            smartLockVO.setSuspend(1);// 0:解冻 1:冻结
                            smartLockVO.setLockFrozenId(frozenSave.getId());
                            smartLockVO.setIndexNum(card.getCardIndexNum());
                            smartLockVO.setIdentification(card.getIdentification());
                            // 亚略特
                            if (smartLock.getBrandId() == 3L) {
                                smartLockVO.setfAuthorizationID(card.getfAuthorizationId());
                            }

                            ResultBean<String> stringResultBean = smartLockBrandService.freezeOrUnfreezeCard(smartLockVO,
                                    smartLock.getBrandId(), XzLockOperatorTypeEnum.CARD.getValue());
                            String msg = stringResultBean.getMsg();
                            String code = stringResultBean.getCode();
                            if (!code.equals(StatusCode.SUCCESS_CODE_10000.getErrorCode())) {
                                log.error("LockAppService frozenOrUnfrozenAuth---> " + msg);
                                // 失败，删除冻结记录
                                lockFrozenRepository.deleteById(frozenSave.getId());
                            } else {
                                // 冻结后默认待执行
                                card.setStatus(0);
                                smartLockCardRepository.save(card);
                                // 亚略特
                                // if (smartLock.getBrandId() == 3L) {
                                yltUpdateStatus(null, card, null, null, null, 1, stringResultBean, smartLockAuth, lockFrozen, smartLock);
                                //}
                            }
                        }
                    }

                    // 指纹锁
                    if (!fingerprint.isEmpty()) {
                        Optional<SmartLockBrand> optional = smartLockBrandRepository.findById(smartLock.getBrandId());
                        if (optional.isPresent()) {
                            SmartLockBrand brand = optional.get();
                            // 品牌支持指纹锁
                            if (brand.getFingerprintStatus() != null && brand.getFingerprintStatus() == 1) {
                                for (SmartLockFingerprint fg : fingerprint) {
                                    SmartLockVO smartLockVO = new SmartLockVO();
                                    smartLockVO.setSn(smartLock.getSn());
                                    smartLockVO.setIndex(fg.getFingerprintIndex());
                                    smartLockVO.setIndexNum(fg.getFingerprintIndexNum());
                                    smartLockVO.setAuthInfoId(lockAuthId);
                                    smartLockVO.setSuspend(1);// 0:解冻 1:冻结
                                    smartLockVO.setLockFrozenId(frozenSave.getId());
                                    smartLockVO.setIndexNum(fg.getFingerprintIndexNum());
                                    // 亚略特
                                    if (smartLock.getBrandId() == 3L) {
                                        smartLockVO.setfAuthorizationID(fg.getfAuthorizationId());
                                    }

                                    ResultBean<String> stringResultBean = smartLockBrandService.freezeOrUnfreezeFingerprint(
                                            smartLockVO, smartLock.getBrandId(), XzLockOperatorTypeEnum.FINGERPRINT.getValue());
                                    String msg = stringResultBean.getMsg();
                                    String code = stringResultBean.getCode();
                                    if (code != StatusCode.SUCCESS_CODE_10000.getErrorCode()) {
                                        log.error("LockAppService deleteUser---> " + msg);
                                        // 失败，删除冻结记录
                                        lockFrozenRepository.deleteById(frozenSave.getId());
                                    } else {
                                        // 冻结后默认待执行
                                        fg.setStatus(0);
                                        smartLockFingerprintRepository.save(fg);
                                        // 亚略特
                                        // if (smartLock.getBrandId() == 3L) {
                                        yltUpdateStatus(null, null, fg, null, null, 1, stringResultBean, smartLockAuth, lockFrozen, smartLock);
                                        //}
                                    }
                                }
                            }
                        }
                    }

                    // 蓝牙
                    if (ble != null) {
                        SmartLockVO smartLockVO = new SmartLockVO();
                        smartLockVO.setSn(smartLock.getSn());
                        smartLockVO.setAuthInfoId(lockAuthId);
                        smartLockVO.setSuspend(1);// 0:解冻 1:冻结
                        smartLockVO.setLockFrozenId(frozenSave.getId());
                        // 亚略特
                        if (smartLock.getBrandId() == 3L) {
                            smartLockVO.setfAuthorizationID(ble.getfAuthorizationId());
                        }
                        ResultBean<String> stringResultBean = smartLockBrandService.freezeOrUnfreezeBle(smartLockVO, smartLock.getBrandId());
                        String msg = stringResultBean.getMsg();
                        String code = stringResultBean.getCode();
                        if (!code.equals(StatusCode.SUCCESS_CODE_10000.getErrorCode())) {
                            log.error("LockAppService frozenOrUnfrozenAuth---> " + msg);
                            // 失败，删除冻结记录
                            lockFrozenRepository.deleteById(frozenSave.getId());
                        } else {
                            // 冻结后默认待执行
                            ble.setStatus(0);
                            smartLockBleRepository.save(ble);
                            // 亚略特
                            // if (smartLock.getBrandId() == 3L) {
                            yltUpdateStatus(null, null, null, ble, null, 1, stringResultBean, smartLockAuth, lockFrozen, smartLock);
                            //}
                        }
                    }

                    // 人脸
                    if (face != null) {
                        SmartLockVO smartLockVO = new SmartLockVO();
                        smartLockVO.setSn(smartLock.getSn());
                        smartLockVO.setAuthInfoId(lockAuthId);
                        smartLockVO.setSuspend(1);// 0:解冻 1:冻结
                        smartLockVO.setLockFrozenId(frozenSave.getId());

                        face.setSn(smartLock.getSn());
                        ResultBean<String> stringResultBean = smartLockBrandService.freezeOrUnfreezeFace(smartLockVO, face, smartLock.getBrandId());
                        String resultData = stringResultBean.getResultData();
                        String msg = stringResultBean.getMsg();
                        String code = stringResultBean.getCode();
                        if (!code.equals(com.mzj.saas.commons.StatusCode.SUCCESS_CODE_10000.getErrorCode())) {
                            log.error("LockAppService frozenOrUnfrozenAuth---> " + msg);
                            // 失败，删除冻结记录
                            lockFrozenRepository.deleteById(frozenSave.getId());
                        } else {
                            face.setReturnFaceId(StrUtil.isEmpty(resultData) ? null : Long.valueOf(resultData));
                            face.setIdentification(resultData);
                            // 冻结后默认待执行
                            face.setStatus(0);
                            smartLockFaceRepository.save(face);
                            // 亚略特
                            // if (smartLock.getBrandId() == 3L) {
                            yltUpdateStatus(null, null, null, null, face, 1, stringResultBean, smartLockAuth, lockFrozen, smartLock);
                            //}
                        }
                    }

                }


                // 更新冻结原因
                smartLock.setReason(chargeName);
                //  写入冻结日志表
                HouseLockFrozenLog houseLockFrozenLog = new HouseLockFrozenLog();
                houseLockFrozenLog.setType(1);// 操作类型: 0:解冻 1:冻结
                houseLockFrozenLog.setLockId(smartLock.getId());// 智能锁绑定id
                houseLockFrozenLog.setHouseId(smartLock.getHouseId()); // 公租房id
                houseLockFrozenLog.setLockAuditId(lockAuthId); // 授权信息id
                houseLockFrozenLog.setOperationId(userId); // 冻结操作人
                houseLockFrozenLog.setOperationTime(new Date()); // 操作时间
                houseLockFrozenLog.setOperationState(2);
                houseLockFrozenLogRepository.save(houseLockFrozenLog);


                /**
                 * 产生智能锁冻结/解冻待办事项
                 */
                addBacklogItem(smartLockAuth.getMobile(), chargeName, 1, smartLock.getHouseId(), smartLockAuth.getAuthorUserId(), userId);
                // 更新亚略特智能锁状态
                yltUpdateLockStatus(smartLock, 1);
                // 更新锁授权人数
                updateOauthNumber(smartLock.getBrandId(), smartLockAuth.getLockId());
            }
            flag = true;
        }
        return flag;
    }

    /**
     * 产生智能锁冻结/解冻待办事项
     *
     * @param mobile     电话
     * @param remark     冻结解冻内容
     * @param type       类型 0:解冻 1:冻结
     * @param houseId    房子ID
     * @param userId     接收人
     * @param operatorId 操作人
     */
    public void addBacklogItem(String mobile, String remark, Integer type, String houseId, String userId, String operatorId) {
        if (type == 1) {
            smsService.sendTemplateSmsWithData(mobile, smsConfig.getLockTemplateCode(), new String[]{remark});
        }


        StringBuilder sql = new StringBuilder();
        sql.append("select a.id ,  \n" +
                "a.org_id as orgId,\n" +
                "b.name AS residenceCommunityName,\n" + // 小区ID
                "c.name AS buildingNumName,\n" +
                "d.name AS unitName ,\n" +
                "a.room_number AS roomNumber \n" +
                "from  saas_house  a\n" +
                "JOIN saas_community b ON b.id = a.  residence_community_id\n" +
                "LEFT JOIN saas_community_build c ON a.building_num = c.id  \n" +
                "LEFT JOIN saas_community_build_unit d ON a.unit = d.id  \n" +
                "where 1=1");

        List<HouseVO> houseList = jdbcTemplate.query(sql.toString() + " and a.id in( '" + houseId + "') ", new BeanPropertyRowMapper<>(HouseVO.class));
        Map<String, HouseVO> houseMap = houseList.stream().collect(Collectors.toMap(HouseVO::getId, a -> a, (k1, k2) -> k1));
        String typeName = null;
        if (type == 1) {
            typeName = "智能锁已冻结";
        } else {
            typeName = "智能锁已解冻";
        }

        // 生成代办事项
        BacklogItem backlogItem = new BacklogItem();
        backlogItem.setHouseId(houseId);// 公租房id
        HouseVO house = houseMap.get(houseId);
        if (null != house) {
            backlogItem.setOrgId(house.getOrgId());// 产权单位id
            if (StringUtils.isNotEmpty(house.getResidenceCommunityName())) {
                backlogItem.setContent(house.getResidenceCommunityName() + house.getBuildingNumName()
                        + "栋" + house.getUnitName() + "单元" + house.getRoomNumber() + "号" + typeName);// 内容   房屋小区-楼栋-单元-房号
            }
        }
        if (type == 1) {
            backlogItem.setTitle("智能锁冻结");// 标题
            backlogItem.setType(32);// 类型：1公租房录入 2智能锁(租金/押金) 3其它费用账单 4资格申请-配租 5备案 6合同到期 13智能锁个人绑定确认 14门锁低电量告警 15门锁离线
            // 16资格审批 17轮候配租 18(合同)租金押金 19生成合同 20合同待确认  30 新增成员 31删除成员 32智能锁冻结  33智能锁解冻', 34 cpu卡冻结

        } else {
            backlogItem.setTitle("智能锁解冻");// 标题
            backlogItem.setType(33);// 类型：1公租房录入 2智能锁(租金/押金) 3其它费用账单 4资格申请-配租 5备案 6合同到期 13智能锁个人绑定确认 14门锁低电量告警 15门锁离线
            // 16资格审批 17轮候配租 18(合同)租金押金 19生成合同 20合同待确认  30 新增成员 31删除成员 32智能锁冻结  33智能锁解冻', 34 cpu卡冻结

        }

        backlogItem.setHandleStatus(0);// 事项处理状态：0未读/未处理  1已读/已处理
        backlogItem.setMatchUserId(userId);// 承租人id/被冻结人
        backlogItem.setOperatorId(operatorId);// 操作人id
        backlogItem.setCreateTime(new Date());// 创建时间
        backlogItem.setPhone(mobile);// 手机号
        BacklogItem save = backlogItemRepository.save(backlogItem);

        BacklogItemCard backlogItemCard = new BacklogItemCard();
        backlogItemCard.setBacklogItemId(save.getId());// 待办事项id
        if (type == 1) {
            backlogItemCard.setType((byte) 1);// 1冻结、2解冻
        } else {
            backlogItemCard.setType((byte) 2);// 1冻结、2解冻
        }
        backlogItemCard.setRemark(remark);// 冻结原因
        backlogItemCard.setOperatorTime(new Date());// 操作时间
        backlogItemCardRefRepository.save(backlogItemCard);
    }

    /**
     * 更新亚略特智能锁状态
     *
     * @param smartLock
     * @param type
     */
    public void yltUpdateLockStatus(SmartLock smartLock, Integer type) {
        try {
            // if (smartLock.getBrandId() == 3L) {
            if (type == 1) {
                if (smartLock.getBindType() == 1) {
                    int authCount = smartLockAuthRepository.findSmartLockAuthByLockId(smartLock.getId());
                    List<SmartLockAuth> auths = smartLockAuthRepository.findByLockIdAndBindTypeAndStatus(smartLock.getId(), 0);
                    if (authCount == auths.size()) {
                        smartLock.setMechineStatus(2);
                        smartLockRepository.save(smartLock);

                        // 全部冻结时, 更新公租房锁授权状态
                        String houseId = smartLock.getHouseId();
                        houseRepository.updateLockStatusById(houseId, 4);
                    }
                } else {
                    int authCount = smartLockAuthRepository.findPersonSmartLockAuthByLockId(smartLock.getId());
                    List<SmartLockAuth> auths = smartLockAuthRepository.findByLockIdAndBindTypeAndStatus(smartLock.getId(), 1);
                    if (authCount == auths.size()) {
                        smartLock.setMechineStatus(2);
                        smartLockRepository.save(smartLock);

                        // 全部冻结时, 更新公租房锁授权状态
                        String houseId = smartLock.getHouseId();
                        houseRepository.updateLockStatusById(houseId, 4);
                    }
                }
            }

            if (type == 0) {
                // 任意授权解冻，更新智能锁设备状态
                smartLock.setMechineStatus(1);
                smartLock.setReason("");
                smartLockRepository.save(smartLock);
            }
            //}
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 更新智能锁授权人数
     *
     * @param brandId
     * @param lockId
     */
    public void updateOauthNumber(Long brandId, Long lockId) {
        try {
            log.info("updateOauthNumber 更新智能锁授权人数, brandId={}, lockId={}", brandId, lockId);

            // if (brandId == 3L) {
            Optional<SmartLock> lockOptional = smartLockRepository.findById(lockId);
            if (!lockOptional.isPresent()) {
                log.info("updateOauthNumber 更新智能锁授权人数, 未找到锁 lockId={}", lockId);
                return;
            }
            SmartLock smartLock = lockOptional.get();
            Integer bindType = smartLock.getBindType();
            Integer bindStatus = smartLock.getBindStatus();

            int oauthNumber = 0;
            if (bindType == 1 && bindStatus == 1) {// 单位锁
                List<SmartLockAuth> auths = smartLockAuthRepository.findByLockIdAndBindType(lockId, 0);

                for (SmartLockAuth auth : auths) {
                    if (auth.getPwdStatus() == 1 || auth.getFingerprintStatus() == 1 || auth.getCardStatus() == 1
                            || auth.getCpuStatus() == 1 || auth.getBleStatus() == 1 || auth.getFaceStatus() == 1) {
                        oauthNumber = oauthNumber + 1;
                    }
                }
            } else if (bindType == 2 && bindStatus == 2) {// 个人锁
                List<SmartLockAuth> auths = smartLockAuthRepository.findByLockIdAndBindType(lockId, 1);

                for (SmartLockAuth auth : auths) {
                    if (auth.getPwdStatus() == 1 || auth.getFingerprintStatus() == 1 || auth.getCardStatus() == 1
                            || auth.getCpuStatus() == 1 || auth.getBleStatus() == 1 || auth.getFaceStatus() == 1) {
                        oauthNumber = oauthNumber + 1;
                    }
                }
            }

            smartLock.setOauthNumber(oauthNumber);
            smartLockRepository.save(smartLock);
            //}
        } catch (Exception e) {
            log.error("更新智能锁授权人数异常" + e.getMessage(), e);
        }
    }

    /*
     *分转换为元
     */
    private String fenToYuan(String amount) {
        NumberFormat format = NumberFormat.getInstance();
        try {
            Number number = format.parse(amount);
            double temp = number.doubleValue() / 100.0;
            format.setGroupingUsed(false);
            // 设置返回的小数部分所允许的最大位数
            format.setMaximumFractionDigits(2);
            amount = format.format(temp);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return amount;
    }

    /**
     * 非公租房其他账单待办事项
     */
    public void propertyOtherItem(Long billId) {
        List<BacklogItemPropertyOtherBill> propertyOtherBill = backlogItemPropertyOtherBillRepository.findByBillId(billId);
        if (propertyOtherBill != null && propertyOtherBill.size() > 0) {
            Date date = new Date();
            for (BacklogItemPropertyOtherBill bill : propertyOtherBill) {
                Optional<BacklogItem> itemOpt = backlogItemRepository.findById(bill.getBacklogItemId());
                if (itemOpt.isPresent()) {
                    BacklogItem item = itemOpt.get();
                    item.setBusinessStatus("已缴费");
                    item.setHandleStatus(1);
                    item.setHandlerTime(date);
                    backlogItemRepository.save(item);
                }
            }
        }

    }

    /**
     * 非公租房租金待办事项
     */
    public void propertyRentItem(Long billId) {
        List<BacklogItemPropertyRentBill> propertyRentBill = backlogItemPropertyRentBillRepository.findByRentBillIdOrDepositBillId(billId, billId);
        if (propertyRentBill != null && propertyRentBill.size() > 0) {
            Date date = new Date();
            for (BacklogItemPropertyRentBill bill : propertyRentBill) {
                Optional<BacklogItem> itemOpt = backlogItemRepository.findById(bill.getBacklogItemId());
                if (itemOpt.isPresent()) {
                    BacklogItem item = itemOpt.get();
                    item.setBusinessStatus("已缴费");
                    item.setHandleStatus(1);
                    item.setHandlerTime(date);
                    backlogItemRepository.save(item);
                }
            }
        }
    }

    /**
     * 亚略特，冻结/解冻操作，更新状态
     *
     * @param pwd
     * @param card
     * @param fg
     * @param type             1冻结，0解冻
     * @param stringResultBean
     * @param smartLockAuth
     * @param lockFrozen
     */
    public void yltUpdateStatus(SmartLockPwd pwd, SmartLockCard card, SmartLockFingerprint fg, SmartLockBle ble, SmartLockFace face, Integer type,
                                ResultBean<String> stringResultBean, SmartLockAuth smartLockAuth, LockFrozen lockFrozen, SmartLock smartLock) {
        try {
            if (pwd != null) {
                // 密码状态
                if (smartLock.getBrandId() == 3) {
                    if (type == 0) {
                        pwd.setfAuthorizationId(stringResultBean.getResultData());
                    }
                }
                pwd.setStatus(1);
                smartLockPwdRepository.save(pwd);

                // 更新用户授权状态
                if (type == 1) {
                    smartLockAuth.setPwdStatus(2);
                } else {
                    smartLockAuth.setPwdStatus(1);
                }
                smartLockAuthRepository.save(smartLockAuth);

                // 更新冻结记录
                lockFrozen.setPwdStatus(1);
                lockFrozenRepository.save(lockFrozen);
            }

            if (card != null) {
                // 卡状态
                if (smartLock.getBrandId() == 3) {
                    if (type == 0) {
                        card.setfAuthorizationId(stringResultBean.getResultData());
                    }
                }
                card.setStatus(1);
                smartLockCardRepository.save(card);

                // 更新用户授权状态
                if (type == 1) {
                    if (card.getType() == 1) {
                        smartLockAuth.setCardStatus(2);
                    } else {
                        smartLockAuth.setCpuStatus(2);
                    }
                } else {
                    if (card.getType() == 1) {
                        smartLockAuth.setCardStatus(1);
                    } else {
                        smartLockAuth.setCpuStatus(1);
                    }
                }
                smartLockAuthRepository.save(smartLockAuth);

                // 更新冻结记录
                if (card.getType() == 1) {
                    lockFrozen.setCardStatus(1);
                } else {
                    lockFrozen.setCpuStatus(1);
                }
                lockFrozenRepository.save(lockFrozen);
            }

            if (fg != null) {
                // 指纹状态
                if (smartLock.getBrandId() == 3) {
                    if (type == 0) {
                        fg.setfAuthorizationId(stringResultBean.getResultData());
                    }
                }
                fg.setStatus(1);
                smartLockFingerprintRepository.save(fg);

                // 更新用户授权状态
                if (type == 1) {
                    smartLockAuth.setFingerprintStatus(2);
                } else {
                    smartLockAuth.setFingerprintStatus(1);
                }
                smartLockAuthRepository.save(smartLockAuth);

                // 更新冻结记录
                lockFrozen.setFingerprintStatus(1);
                lockFrozenRepository.save(lockFrozen);
            }

            if (ble != null) {
                // 指纹状态
                if (smartLock.getBrandId() == 3) {
                    if (type == 0) {
                        ble.setfAuthorizationId(stringResultBean.getResultData());
                    }
                }
                ble.setStatus(1);
                smartLockBleRepository.save(ble);

                // 更新用户授权状态
                if (type == 1) {
                    smartLockAuth.setBleStatus(2);
                } else {
                    smartLockAuth.setBleStatus(1);
                }
                smartLockAuthRepository.save(smartLockAuth);

                // 更新冻结记录
                lockFrozen.setBleStatus(1);
                lockFrozenRepository.save(lockFrozen);
            }

            if (face != null) {
                face.setStatus(1);
                smartLockFaceRepository.save(face);

                // 更新用户授权状态
                if (type == 1) {
                    smartLockAuth.setFaceStatus(2);
                } else {
                    smartLockAuth.setFaceStatus(1);
                }
                smartLockAuthRepository.save(smartLockAuth);

                // 更新冻结记录
                lockFrozen.setFaceStatus(1);
                lockFrozenRepository.save(lockFrozen);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 非公租房其他费用账单待办事项
     *
     * @param houseId        房屋ID
     * @param rentBillId     账单ID
     * @param billChargeType 账单类型
     * @param cost           金额
     * @param operatorId     操作人
     */
    public void payEstateExpenseBillItem(String houseId, Long rentBillId, Integer billChargeType, Integer cost, String operatorId, EstateExpenseBill expenseBill) {
        String yuan = fenToYuan(String.valueOf(cost));
        String chargeName = null;
        switch (billChargeType) {  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费
            case 1:
                chargeName = "水费";
                break;
            case 2:
                chargeName = "电费";
                break;
            case 3:
                chargeName = "物业费";
                break;
            case 4:
                chargeName = "宽带费";
                break;
            case 5:
                chargeName = "电视费";
                break;
            case 6:
                chargeName = "燃气费";
                break;
            case 7:
                chargeName = "暖气费";
                break;
        }

//        String sql="select * from (\n" +
//                "select a.mobile as mobile ,a.community_house_id as houseId  , a.user_id as userId  from  saas_community_house_user a\n" +
//                "where   a.status = 1 \n" +
//                "UNION\n" +
//                "select b.phone as mobile , a.house_id as houseId , a.match_user_id as userId from   saas_house_match_user a \n" +
//                "LEFT JOIN saas_app_user b on b.id= a.match_user_id\n" +
//                "where 1=1\n" +
//                "UNION \n" +
//                "select b.mobile as mobile , a.house_id as houseId , c.id as userId from   saas_house_match_user a \n" +
//                "LEFT JOIN saas_house_eligible_apply_cohabit b on b.apply_id= a.apply_id\n" +
//                "LEFT JOIN saas_app_user c on c.phone = b.mobile \n" +
//                "where 1=1 and b.mobile is not null \n" +
//                ") t1 where t1.houseId ='"+houseId+"' ";

        /**
         * xin
         * 2022-09-20 13:42
         * 账单审核后只有承租人能收到短信
         */
        String sql = "select * from (\n" +
                "select a.mobile as mobile ,a.community_house_id as houseId  , a.user_id as userId  from  saas_community_house_user a\n" +
                "where   a.status = 1 and   a.type = 1\n" +
                "UNION\n" +
                "select b.phone as mobile , a.house_id as houseId , a.match_user_id as userId from   saas_house_match_user a\n" +
                "LEFT JOIN saas_app_user b on b.id= a.match_user_id\n" +
                "where 1=1\n" +
                ") t1 where t1.houseId ='" + houseId + "' ";


        String where = " and 1=1 ";
        if (StringUtils.isNotBlank(expenseBill.getMatchUserId())) {
            where = " or t1.userId = '" + expenseBill.getMatchUserId() + "'";
        }

        List<CommunityHouseUser> CommunityHouseUserList = jdbcTemplate.query(sql + where, new BeanPropertyRowMapper<>(CommunityHouseUser.class));

        CommunityHouseUserList = CommunityHouseUserList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(CommunityHouseUser::getMobile))), ArrayList::new));
        for (CommunityHouseUser communityHouseUser : CommunityHouseUserList) {
            AppUser appUser = appUserRepository.findByPhone(communityHouseUser.getMobile());

            // 非公租房其他费用账单待办事项
            BacklogItem backlogItem = new BacklogItem();
            backlogItem.setHouseId(houseId);
            backlogItem.setType(BacklogItemTypeEnum.PROPERTY_OTHER_BILL.getValue());
            backlogItem.setTitle(chargeName + "账单待缴费");
            backlogItem.setContent(chargeName + "账单，请尽快缴费");
            backlogItem.setBusinessStatus("待缴费");
            backlogItem.setHandleStatus(0);
            backlogItem.setOperatorId(operatorId);// 操作人id
            if (appUser != null) {
                backlogItem.setMatchUserId(appUser.getId());
            }
            backlogItem.setPhone(communityHouseUser.getMobile());
            backlogItem.setCreateTime(new Date());
            BacklogItem save = backlogItemRepository.save(backlogItem);

            BacklogItemPropertyOtherBill propertyOtherBill = new BacklogItemPropertyOtherBill();
            propertyOtherBill.setBacklogItemId(save.getId());
            propertyOtherBill.setBillId(rentBillId);

            backlogItemPropertyOtherBillRepository.save(propertyOtherBill);
            // 账单生成短信
            smsService.sendTemplateSmsWithData(communityHouseUser.getMobile(), smsConfig.getBillTemplateCode(), new String[]{chargeName, yuan});

        }

    }

    /**
     * 非公租房租金/押金待办事项
     *
     * @param houseId        房屋ID
     * @param rentBillId     账单ID
     * @param billChargeType 收费项目:1租金 2押金
     * @param cost           金额
     * @param operatorId     操作人
     */
    public void payEstateRentBillItem(String houseId, Long rentBillId, Integer billChargeType, Integer cost, String operatorId, EstateRentBill rentBill) {

        String yuan = fenToYuan(String.valueOf(cost));
        String chargeName = billChargeType == 1 ? "租金" : "押金";

        String sql = "select * from (\n" +
                "select a.mobile as mobile ,a.community_house_id as houseId  , a.user_id as userId  from  saas_community_house_user a\n" +
                "where   a.status = 1 \n" +
                "UNION\n" +
                "select b.phone as mobile , a.house_id as houseId , a.match_user_id as userId from   saas_house_match_user a \n" +
                "LEFT JOIN saas_app_user b on b.id= a.match_user_id\n" +
                "where 1=1\n" +
                "UNION \n" +
                "select b.mobile as mobile , a.house_id as houseId , c.id as userId from   saas_house_match_user a \n" +
                "LEFT JOIN saas_house_eligible_apply_cohabit b on b.apply_id= a.apply_id\n" +
                "LEFT JOIN saas_app_user c on c.phone = b.mobile \n" +
                "where 1=1 and b.mobile is not null \n" +
                ") t1 where t1.houseId ='" + houseId + "' ";

        String where = " and 1=1 ";
        if (StringUtils.isNotBlank(rentBill.getMatchUserId())) {
            where = " or t1.userId = '" + rentBill.getMatchUserId() + "'";
        }

        List<CommunityHouseUser> CommunityHouseUserList = jdbcTemplate.query(sql + where, new BeanPropertyRowMapper<>(CommunityHouseUser.class));

        CommunityHouseUserList = CommunityHouseUserList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(CommunityHouseUser::getMobile))), ArrayList::new));

        for (CommunityHouseUser communityHouseUser : CommunityHouseUserList) {
            AppUser appUser = appUserRepository.findByPhone(communityHouseUser.getMobile());

            // 生成非公租房租金/押金待办事项
            BacklogItem backlogItem = new BacklogItem();
            backlogItem.setHouseId(houseId);
            backlogItem.setType(BacklogItemTypeEnum.PROPERTY_BILL_RENT.getValue());
            backlogItem.setTitle(chargeName + "账单待缴费");
            backlogItem.setContent(chargeName + "账单，请尽快缴费");
            backlogItem.setBusinessStatus("待缴费");
            backlogItem.setHandleStatus(0);
            backlogItem.setOperatorId(operatorId);// 操作人id
            if (appUser != null) {
                backlogItem.setMatchUserId(appUser.getId());
            }
            backlogItem.setPhone(communityHouseUser.getMobile());
            backlogItem.setCreateTime(new Date());
            BacklogItem save = backlogItemRepository.save(backlogItem);

            BacklogItemPropertyRentBill PropertyRentBill = new BacklogItemPropertyRentBill();
            PropertyRentBill.setBacklogItemId(save.getId());
            if (appUser != null) {
                PropertyRentBill.setMatchUserId(appUser.getId());
            }

            if (billChargeType == 1) {
                PropertyRentBill.setRentBillId(rentBillId);// 租金账单id
            } else {
                PropertyRentBill.setDepositBillId(rentBillId);// 押金账单id
            }
            backlogItemPropertyRentBillRepository.save(PropertyRentBill);
            // 账单生成短信
            smsService.sendTemplateSmsWithData(communityHouseUser.getMobile(), smsConfig.getBillTemplateCode(), new String[]{chargeName, yuan});
        }

    }

    /**
     * 非公租房其他费用账单待办事项
     *
     * @param houseId        房屋ID
     * @param rentBillId     账单ID
     * @param billChargeType 账单类型
     * @param operatorId     操作人
     */
    public void propertyOtherItem(String houseId, Long rentBillId, Integer billChargeType, String operatorId, String matchUserId) {
        Optional<House> byId = houseRepository.findById(houseId);
        House house = byId.get();
        String communityName = "";
        String buildingNumName = "";
        String unitName = "";


        String houseSql = "SELECT\n" +
                "\tsc.`name` AS communityName, scb.`name` AS buildingNumName,\n" +
                "\tscbu.`name` AS unitName,h.room_number AS roomNumber\n" +
                "\t\n" +
                "FROM\n" +
                "\tsaas_house h\n" +
                "\tJOIN saas_community sc ON h.residence_community_id = sc.id\n" +
                "\tJOIN saas_community_build scb ON h.building_num = scb.id\n" +
                "\tJOIN saas_community_build_unit scbu ON h.unit = scbu.id where h.id = '" + houseId + "'";


        List<Map<String, Object>> maps = jdbcTemplate.queryForList(houseSql);
        for (Map<String, Object> map : maps) {
            communityName = String.valueOf(map.get("communityName"));
            buildingNumName = String.valueOf(map.get("buildingNumName"));
            unitName = String.valueOf(map.get("unitName"));
        }


        String chargeName = "";
        switch (billChargeType) {  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费
            case 1:
                chargeName = "水费";
                break;
            case 2:
                chargeName = "电费";
                break;
            case 3:
                chargeName = "物业费";
                break;
            case 4:
                chargeName = "宽带费";
                break;
            case 5:
                chargeName = "电视费";
                break;
            case 6:
                chargeName = "燃气费";
                break;
            case 7:
                chargeName = "暖气费";
                break;
            case 8:
                chargeName = "租金";
                break;
            case 9:
                chargeName = "押金";
                break;
        }

//        String sql="select * from (\n" +
//                "select a.mobile as mobile ,a.community_house_id as houseId  , a.user_id as userId  from  saas_community_house_user a\n" +
//                "where   a.status = 1 \n" +
//                "UNION\n" +
//                "select b.phone as mobile , a.house_id as houseId , a.match_user_id as userId from   saas_house_match_user a \n" +
//                "LEFT JOIN saas_app_user b on b.id= a.match_user_id\n" +
//                "where 1=1\n" +
//                "UNION \n" +
//                "select b.mobile as mobile , a.house_id as houseId , c.id as userId from   saas_house_match_user a \n" +
//                "LEFT JOIN saas_house_eligible_apply_cohabit b on b.apply_id= a.apply_id\n" +
//                "LEFT JOIN saas_app_user c on c.phone = b.mobile \n" +
//                "where 1=1 and b.mobile is not null \n" +
//                ") t1 where t1.houseId ='"+houseId+"' ";

        /**
         * xin
         * 2022-09-20 13:42
         * 账单审核后只有承租人能收到短信
         */
        String sql = "select * from (\n" +
                "select a.mobile as mobile ,a.community_house_id as houseId  , a.user_id as userId  from  saas_community_house_user a\n" +
                "where   a.status = 1 and   a.type = 1\n" +
                "UNION\n" +
                "select b.phone as mobile , a.house_id as houseId , a.match_user_id as userId from   saas_house_match_user a\n" +
                "LEFT JOIN saas_app_user b on b.id= a.match_user_id\n" +
                "where 1=1\n" +
                ") t1 where t1.houseId ='" + houseId + "' ";


        String where = " and 1=1 ";
        if (StringUtils.isNotBlank(matchUserId)) {
            where = " or t1.userId = '" + matchUserId + "'";
        }

        List<CommunityHouseUser> CommunityHouseUserList = jdbcTemplate.query(sql + where, new BeanPropertyRowMapper<>(CommunityHouseUser.class));

        CommunityHouseUserList = CommunityHouseUserList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(CommunityHouseUser::getMobile))), ArrayList::new));
        for (CommunityHouseUser communityHouseUser : CommunityHouseUserList) {
            AppUser appUser = appUserRepository.findByPhone(communityHouseUser.getMobile());

            List<BacklogItemPropertyOtherBill> byBillId = backlogItemPropertyOtherBillRepository.findByBillId(rentBillId);
            if (byBillId.isEmpty()) {
                // 非公租房其他费用账单待办事项
                BacklogItem backlogItem = new BacklogItem();
                backlogItem.setHouseId(houseId);
                backlogItem.setType(BacklogItemTypeEnum.PROPERTY_OTHER_BILL.getValue());
                backlogItem.setTitle(chargeName + "违约金账单待缴费");
                backlogItem.setContent(communityName + buildingNumName + "栋" + unitName + "单元" + house.getRoomNumber() + "房，" + chargeName + "违约金账单已生成，请尽快缴费");
                backlogItem.setBusinessStatus("待缴费");
                backlogItem.setHandleStatus(0);
                backlogItem.setOperatorId(operatorId);// 操作人id
                if (appUser != null) {
                    backlogItem.setMatchUserId(appUser.getId());
                }
                backlogItem.setPhone(communityHouseUser.getMobile());
                backlogItem.setCreateTime(new Date());
                BacklogItem save = backlogItemRepository.save(backlogItem);

                BacklogItemPropertyOtherBill propertyOtherBill = new BacklogItemPropertyOtherBill();
                propertyOtherBill.setBacklogItemId(save.getId());
                propertyOtherBill.setBillId(rentBillId);

                backlogItemPropertyOtherBillRepository.save(propertyOtherBill);
            } else {
                BacklogItemPropertyOtherBill backlogItemPropertyOtherBill = byBillId.get(0);
                Optional<BacklogItem> backlogItem = backlogItemRepository.findById(backlogItemPropertyOtherBill.getBacklogItemId());
                BacklogItem item = backlogItem.get();
                item.setCreateTime(new Date());
            }
        }

    }


}
